1

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

所以我创建了一个新项目来尝试识别和解决问题,它揭示了问题的更多细节。当我在家时,我可以提供示例和视频,但我现在将描述。使用 TScrollBox 制作了一个 spinedit 表单,以指定一个按钮在循环中创建面板的数量以及一个用于释放面板并清空数组以供再次尝试的按钮。我将标题设置为循环中的数字以进行识别。

我尝试了 2 种堆叠方式,看看是否重要。一种是设置位置 I 乘以高度,因此如果高度为 200,则 i * 202 给它一个 2px 的空间。我尝试的新方法是使用 align top 。它可能在效果上略有不同,但总的来说问题仍然相同。

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

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

在我的应用程序中设置位置而不是使用 align top 时出现的主要问题是,在一定数量的面板之后,它们都位于同一位置的末尾。在一定数量之前,它的罚款说是 50 或 100,但在发生了这么多之后。我知道 200 乘以 200 是一个很小的整数,但也许有地址限制?

我将继续测试我仍然需要检查面板高度是否添加到其中。但认为这必须是一个已知问题。顺便说一句,德尔福 2009。

4

1 回答 1

7

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

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

参数

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

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

因此宽度和高度值限制为 16 位。即:当SetWindowPos涉及到或类似时,由SetBounds调用,由设置调用Top

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

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

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


怎么解决?

Top滚动框内的子控件的属性是相对于该框的可见客户端区域的;滚动滚动条会重置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(a TWinControl),使用TControl衍生产品绕过对SetWindowPos.


怎么解决最好?

使用虚拟方法,就像这样TDBControlGrid做一样,只显示几个面板,同时给人一种有很多的印象。

于 2013-02-01T23:20:14.147 回答