Delphi - TScrollBox问题后X个组件 [英] Delphi - TScrollBox issue after X number of components

查看:301
本文介绍了Delphi - TScrollBox问题后X个组件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在我的一个测试应用程序中注意到,在我添加了如此多的TPanels到TScrollBox后,我遇到了一些问题。我在绘制之前禁用滚动框,并且在绘制之前总是被清除,因此没有相对位置问题。最初我以为也许我遇到了一些最大的高度来画画。所以你知道这个安排是垂直堆叠的宽度占用面板。



所以我创建了一个新项目来尝试识别和解决问题,并且显示了一个额外的细节问题。当我回家的时候,我可以提供一个例子和一个视频,但现在我将会描述。用TScrollBox做一个spinedit的表单来指定一个按钮在一个循环中创建面板的按钮,以及一个按钮来释放面板并清空数组以进行另一次尝试。我将标题设置为循环中的号码进行识别。



我已经尝试了两种堆叠方式,以查看位是否重要。一个是设置位置I倍高度,所以如果height是200,那么我* 202给它一个2px的空间。我尝试的新方法是使用对齐顶部。它可能有一个微小的差异,但一般的问题仍然是一样的。



新的问题是滚动范围。循环完成后,滚动框可以滚动到最后编号面板的底部。但它的位置可能是199在169它的200面板。然后滚动条调整范围,让我到达底部才能看到最后面板198的下一个。我相信这是使用对齐顶部方法,因为它从未在我的应用程序中发生。我会进一步测试。



底部面板不放在一边我认为该问题的解决方案是手动计算和设置范围。



在设置位置而不是使用对齐顶部时,在我的应用程序中发生的主要问题是,在一定数量的面板之后,它们都位于同一位置。在一定数量之前,罚款是50或100,但经过这么多事情发生。我知道200次200是一个很小的整数,但也许有一个地址限制?



我将继续测试,我仍然需要检查是否增加面板高度。但是想到这是一个已知的问题。

解决方案

这是Windows限制:Windowed控件的大小不能超过65,535像素。 >

请参阅 WM_SIZE消息,其中宽度和高度以单个32位参数传递在一起:


lParam



lParam的低位词指定客户区域的新宽度。



lParam的高位词指定客户区域的新高度。


因此,width和height值限制为16位。也就是说:当 SetWindowPos 或相似的方式,由 SetBounds 调用,通过设置顶部



随后,控件的 Top 值可以为负,限制在15位和1位符号位,因此+ -32,767。具体说来:那就是 Control.ClientOrigin.X / Y 的绑定。例如。因此,对于放置在1920x1200像素屏幕中间的控件,解析最大顶部值为32,167。



所以这就是为什么最后一个面板出现在滚动条中的同一个位置。



请注意,此限制不适用于没有Windows句柄的VCL控件。






如何解决?



/ code>滚动框内的子控件的属性是相对于框的可见客户端;滚动滚动条将重置所有孩子的顶部属性。



所以(只是)达到魔法极限之前,愚弄Windows滚动滚动框:

  procedure TForm1.Button1Click(Sender:TObject); 
var
I:整数;
J:整数;
P:TPanel;
begin
ScrollBox1.DisableAlign;
try
ScrollBox1.VertScrollBar.Range:= 400 * 202; // 80,800! ; -)
为I:= 0到3 do
begin
ScrollBox1.VertScrollBar.Position:= I * 100 * 202;
为J:= 0到99 do
begin
P:= TPanel.Create(Self);
P.SetBounds(0,J * 202,100,200);
P.Align:= alCustom;
P.Caption:= IntToStr(I * 100 + J);
P.ParentBackground:= False;
P.Color:=随机(clWhite);
P.Parent:= ScrollBox1;
结束
结束
finally
ScrollBox1.VertScrollBar.Position:= 0;
ScrollBox1.EnableAlign;
结束
结束






如何更好地解决?



而不是 TPanel (a TWinControl ),使用 TControl 衍生物绕过API调用 SetWindowPos






如何最好地解决?



使用虚拟方法,如 TDBControlGrid 只显示几张面板,同时给人印象很深。


I noticed in one of my test applications after I have added so many TPanels to a TScrollBox I run into a problem with the ones drawn past that certain amount. I disable the scroll box prior to drawing and it is always cleared before drawing so there are no relative position problems. Initially I thought maybe I had run into some sort of maximum height to paint. So you know the arrangement is width occupying panels stacked vertically.

So I created a new project to try and identify and tackle the problem and it has revealed an additional detail to the problem. When I'm home I can provide the example and a video but I will describe for now. Made a form with a TScrollBox a spinedit to specify how many panels a button to create the panels in a loop and a button to free the panels and empty the array for another try. I set the caption to the number in the loop for identification.

I have tried 2 ways of stacking to see if bit mattered. One is to set the position I times height so if height is 200 then i * 202 giving it a space of 2px. The new way I tried was using align top instead. It might have a slight difference in effect but the problem in general is still the same.

The new problem is with the scroll range. After the loop is done and the scroll box is enabled scrolling down to the bottom stops at the last numbered panel. But its out of place maybe 199 right below 169 its 200 panels. Then the scroll bar adjusts range letting me reach the bottom only to see the next to last panel 198. I believe this occurs using the align top method as it never occurred in my app. I will test further.

Bottom panel not placing aside I think the solution to that problem is to manually calculate and set the range.

The main problem which occurs in my app when setting the position instead of using align top is that after a certain number of panels they all position at the end in the same spot. Before a certain amount its fine say 50 or 100 but after so many it happens. I know 200 times 200 is a pretty small integer but maybe there is a address limit?

I will continue to test I still need to check if panel height adds into it. But figured this has to be a known issue. Delphi 2009 by the way.

解决方案

It's a Windows limitation: the size of a Windowed control cannot exceed 65,535 pixels.

See the documentation on the WM_SIZE message wherein width and height are passed together in a single 32 bit parameter:

lParam

The low-order word of lParam specifies the new width of the client area.

The high-order word of lParam specifies the new height of the client area.

So width and height values are limited to 16 bits. That is: when SetWindowPos or alike is involved, which is called by SetBounds, which is called by setting Top.

Subsequently, the Top value of a control, which can be negative, is limited to 15 bits and 1 sign bit, thus +-32,767. To be specific: that is where Control.ClientOrigin.X/Y is bound by. E.g. thus resolving in a maximum Top value of 32,167 for a control placed in the middle of a 1920x1200 pixel screen.

So this is why the last panels appear on the same spot within your scroll box.

Note that this limitation does not apply to VCL controls without Windows handle.


How to solve?

The Top property of a child control within a scroll box is relative to the box's visible clientrect; scrolling the scroll bar resets the Top properties of all children.

So (just) before reaching the magic limit, fool Windows by scrolling the scroll box:

procedure TForm1.Button1Click(Sender: TObject);
var
  I: Integer;
  J: Integer;
  P: TPanel;
begin
  ScrollBox1.DisableAlign;
  try
    ScrollBox1.VertScrollBar.Range := 400 * 202; // 80,800 ! ;-)
    for I := 0 to 3 do
    begin
      ScrollBox1.VertScrollBar.Position := I * 100 * 202;
      for J := 0 to 99 do
      begin
        P := TPanel.Create(Self);
        P.SetBounds(0, J * 202, 100, 200);
        P.Align := alCustom;
        P.Caption := IntToStr(I * 100 + J);
        P.ParentBackground := False;
        P.Color := Random(clWhite);
        P.Parent := ScrollBox1;
      end;
    end;
  finally
    ScrollBox1.VertScrollBar.Position := 0;
    ScrollBox1.EnableAlign;
  end;
end;


How to solve it better?

Instead of TPanel (a TWinControl), use TControl derivatives to bypass API calls to SetWindowPos.


How to solve it best?

Use a virtual approach, like TDBControlGrid does, showing only a few panels while giving the impression of having a lot.

这篇关于Delphi - TScrollBox问题后X个组件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆