Delphi - 在X个组件之后发出TScrollBox问题

时间:2013-02-01 21:42:10

标签: delphi delphi-2009

我在我的一个测试应用程序中注意到,在我向TScrollBox添加了这么多TPanel后,我遇到了一些超出一定数量的问题。我在绘制之前禁用了滚动框,并且在绘制之前总是清除它,因此没有相对位置问题。最初我想也许我已经遇到了某种最大高度的油漆。所以你知道这种排列是宽度占据面板垂直堆叠。

因此,我创建了一个新项目来尝试识别并解决问题,并且已经揭示了该问题的其他细节。当我在家时,我可以提供示例和视频,但我现在将介绍。制作一个带有TScrollBox spinedit的表单,用于指定按钮在循环中创建面板的面板数量,以及用于释放面板并清空阵列以进行另一次尝试的按钮。我将标题设置为循环中的数字以进行识别。

我尝试了两种堆叠方式,看看是否有点重要。一个是设置位置I乘以高度,所以如果高度为200则i * 202给它一个2px的空间。我尝试的新方法是使用对齐顶部。效果可能略有不同,但问题一般都是一样的。

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

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

设置位置而不是使用对齐顶部时,我的应用程序中出现的主要问题是,在一定数量的面板之后,它们都位于同一位置的末端。在一定数量之前它的罚款说50或100,但在这么多之后它会发生。我知道200次200是一个非常小的整数但可能有一个地址限制?

我将继续测试我仍然需要检查面板高度是否加入其中。但认为这必须是一个已知的问题。顺便提一下Delphi 2009。

1 个答案:

答案 0 :(得分:5)

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

请参阅WM_SIZE message上的文档,其中宽度和高度在一个32位参数中一起传递:

  

lParam的

     

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

     

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

因此宽度和高度值限制为16位。也就是说:当涉及SetWindowPos或类似时,由SetBounds调用,通过设置Top来调用。

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

因此,这就是为什么最后一个面板出现在滚动框中的同一位置。

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


如何解决?

滚动框中子控件的Top属性是相对于框的可见clientrect;滚动滚动条会重置所有子项的Top属性。

所以(只是)在达到魔法限制之前,通过滚动滚动框来愚弄Windows:

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;

如何更好地解决?

使用TPanel衍生产品来绕过TWinControl的API调用,而不是TControlSetWindowPos)。


如何最好地解决?

使用虚拟方法,例如TDBControlGrid,只显示几个面板,同时给人留下很多印象。