'TScrollBox without scrollbars

I want to dynamically create some buttons in a TScrollBox (that has VertScrollBar.Vissible= False).

I want to programmatically bring some of those buttons in view, so I would like to use something like:

  ScrollBox.VertScrollBar.Position:= i; //Does not work

However, the box won't scroll to the indicated position unless the VertScrollBar.Vissible= True. Note: ScrollBy() works, but I don't want to use that.

How to circumvent this behavior?

(A "solution" would be to let the scrollbars visible and hide them outside the screen (place the scrollbox in a panel))


Code:

unit UnitVert;

interface

uses
  System.SysUtils, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm3 = class(TForm)
    ScrollBox1: TScrollBox;
    Button1: TButton;
    Button2: TButton;
    procedure Button2Click(Sender: TObject);
  end;

var
  Form3: TForm3;

implementation {$R *.dfm}

procedure TForm3.Button2Click(Sender: TObject);
begin
  ScrollBox1.VertScrollBar.Position:= -20;
  //ScrollBox1.ScrollBy(0, -20);     //Works
end;

end.

object Form3: TForm3
  Left = 0
  Top = 0
  Caption = 'Form3'
  ClientHeight = 336
  ClientWidth = 635
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object ScrollBox1: TScrollBox
    Left = 176
    Top = 75
    Width = 283
    Height = 203
    HorzScrollBar.Visible = False
    VertScrollBar.Visible = False
    TabOrder = 0
    object Button1: TButton
      Left = 188
      Top = 132
      Width = 123
      Height = 99
      Caption = 'Dummy'
      TabOrder = 0
    end
  end
  object Button2: TButton
    Left = 26
    Top = 50
    Width = 111
    Height = 51
    Caption = 'Test'
    TabOrder = 1
    OnClick = Button2Click
  end
end


Solution 1:[1]

Works as expected

Cannot reproduce your issue with D7 on Win7:

Scrollbox1.HorzScrollBar.Visible:= FALSE;
Scrollbox1.VertScrollBar.Visible:= FALSE;
Scrollbox1.ScrollBy( -30, -45 );

...moves the viewport 30 px to the left and 45 px to the top. Also note that the first parameter is X (horizontal) and the second parameter is Y (vertical) - actually anything I've seen in life was always in the X,Y order.

Why invisible scrollbars won't work

The method TWinControl.ScrollBy() includes this code:

IsVisible := (FHandle <> 0) and IsWindowVisible(FHandle);
if IsVisible then ScrollWindow(FHandle, DeltaX, DeltaY, nil, nil);

...which means: it is essentially using the WinAPI's ScrollWindow() function. Changing the position of one of the scrollbars executes TControlScrollBar.SetPosition(), which in turn calls .ScrollBy() again for just one dimension:

OldPos := FPosition;
if Kind = sbHorizontal then
  FControl.ScrollBy(OldPos - Value, 0) else
  FControl.ScrollBy(0, OldPos - Value);

...and since this time the parent control is the scrollbar (not the scrollbox) its invisibility prevents the WinAPI function from being called. Content wise there's no gain in using scrollbars - they just conveniently remember what you already scrolled.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1