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

Viewed 558

I want to change the caption of a panel when it is out of view when scrolling in a TScrollBox. I have a scrollbox where all the all the categories are listed under each other and as the title of each category scrolls past i want the top panel to change to show which category I am currently scrolling through. How exactly can i do this?

1 Answers

To see if any pixel of a child control ChildCtrl currently is visible in the parent TScrollBox control named ScrollBox, check

ScrollBox.ClientRect.IntersectsWith(ChildCtrl.BoundsRect)

This is just one definition of "not out of view", however. If you instead want to check if the entire control is visible, instead check

ScrollBox.ClientRect.Contains(ChildCtrl.BoundsRect)

To detect scrolling, you would love a published OnScroll property of TScrollBox, but unfortunately there is no such property. Instead, you must intercept the scroll messages yourself, as detailed in this Q&A.


Here is a complete example (just quick and dirty to show how it is done -- in a real app, you would refactor it):

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.

Screenshot of a scroll box containing a vertical array of buttons being scrolled. The caption of the first completely visible button (from the top) is displayed in a label above the scroll box.

Don't forget to set TScrollBox.VertScrollBar.Tracking to True!

Related