【问题标题】:Delphi - TScrollBox issue after X number of componentsDelphi - X个组件后的TScrollBox问题
【发布时间】:2013-02-01 21:42:09
【问题描述】:

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

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

我尝试了 2 种堆叠方式,看看是否重要。一种是设置位置 I 乘以高度,因此如果高度为 200,则 i * 202 给它一个 2px 的空间。我尝试的新方法是使用 align top 。效果上可能会有细微差别,但大体上问题还是一样的。

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

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

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

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

【问题讨论】:

  • 请向质量中心提交错误报告。这也是搜索已知错误的地方。

标签: delphi delphi-2009


【解决方案1】:

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

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

l参数

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

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

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

随后,控件的Top 值(可以为负数)被限制为 15 位和 1 个符号位,因此为 +-32,767。具体来说:这就是Control.ClientOrigin.X/Y 所绑定的地方。例如。因此,对于放置在 1920x1200 像素屏幕中间的控件,最大 Top 值解析为 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;

如何更好地解决?

使用TControl 派生类来绕过对SetWindowPos 的API 调用,而不是TPanelTWinControl)。


如何最好地解决?

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

【讨论】:

  • 好的,谢谢。我将继续我的计划,限制加载数据 X 个文件,并且只加载下一个之前的文件。由于下载时间的原因,它最初是可选的,但现在它将被强制执行。我确信还存在其他选项,例如在滚动后加载可视控件等,但很高兴知道原因。
  • 你需要使用虚拟范式。
猜你喜欢
  • 2023-03-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-16
  • 2015-10-14
  • 2013-11-01
  • 1970-01-01
相关资源
最近更新 更多