在 delphi 的滚动框中滚动时,如何查看组件是否超出视图?

How to see if a component is out of view when scrolling in a scrollbox in delphi?

我想在 TScrollBox 中滚动时更改不在视图中的面板的标题。我有一个滚动框,其中所有类别都在彼此下方列出,并且随着每个类别的标题滚动过去,我希望顶部面板更改以显示我当前正在滚动的类别。我该怎么做?

要查看子控件 ChildCtrl 的任何像素当前是否在名为 ScrollBox 的父 TScrollBox 控件中可见,请检查

ScrollBox.ClientRect.IntersectsWith(ChildCtrl.BoundsRect)

然而,这只是“不在视野之外”的一种定义。如果您想检查 entire 控件是否可见,请改为检查

ScrollBox.ClientRect.Contains(ChildCtrl.BoundsRect)

要检测滚动,您会喜欢已发布的 OnScroll 属性 of TScrollBox,但不幸的是没有这样的 属性。相反,您必须自己拦截滚动消息,详见 in this Q&A.


这是一个完整的示例(只是简单粗暴地展示它是如何完成的——在真实的应用程序中,您将重构它):

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, StdCtrls;

type
  TScrollBox = class(Vcl.Forms.TScrollBox)
    procedure WMVScroll(var Message: TWMVScroll); message WM_VSCROLL;
  end;

  TForm1 = class(TForm)
    ScrollBox1: TScrollBox;
    lblTitle: TLabel;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    FButtons: TArray<TButton>;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
const
  N = 30;
var
  i, y: Integer;
  btn: TButton;
begin

  // First, populate the scroll box with some sample buttons

  SetLength(FButtons, N);

  y := 10;
  for i := 0 to N - 1 do
  begin
    btn := TButton.Create(ScrollBox1);
    btn.Parent := ScrollBox1;
    btn.Left := 10;
    btn.Top := y;
    btn.Caption := 'Button ' + (i + 1).ToString;
    Inc(y, 3*btn.Height div 2);
    FButtons[i] := btn;
  end;

end;

{ TScrollBox }

procedure TScrollBox.WMVScroll(var Message: TWMVScroll);
var
  i: Integer;
begin

  inherited;

  for i := 0 to High(Form1.FButtons) do
    if Form1.ScrollBox1.ClientRect.Contains(Form1.FButtons[i].BoundsRect) then
    begin
      Form1.lblTitle.Caption := Form1.FButtons[i].Caption;
      Break;
    end;

end;

end.

不要忘记将TScrollBox.VertScrollBar.Tracking设置为True