2010. május 28., péntek
How to synchronize the scrolling of three TScrollBoxes when only one shows a scrollbar
Problem/Question/Abstract:
I need to synchronize three scrollboxes, only one of which will show the scrollbars. The documentation for TControlScrollBar reads: "If Visible is set to False, the scroll bar is never visible. This is useful, for example, for programmatically controlling the scroll position of a form without allowing the user to control the scroll position." I have been unable to make the scrollbox scroll when the scrollbar is visible. In fact, the moment you set the scrollbar to invisible, the position jumps back to 0.
Answer:
I looked at the VCL source for TScrollbox and TControlScrollbar and found the source of the problem: the TControlscrollbar class has an internal field named FCalcRange. If you try to set the scrollbar position the passed position is clipped to the range 0..FCalcRange. The only problem is that FCalcRange is set to 0 when the scrollbar is set to invisible, so Position will always be set to 0, regardless of what you try to set it to. I see no way around that, so you need to use a different strategy: instead of using the invisible scrollbars for the two slave scrollboxes scroll them directly, using ScrollBy.
The following example uses three scrollboxes of same size and scroll ranges. AutoScroll and Autosize are false for all, the first two have invisible scrollbars, the last has visible scrollbars and controls the other two. Each scrollbox has an edit in it so there is something visible to scroll around.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
type
TForm1 = class(TForm)
ScrollBox1: TScrollBox;
Edit1: TEdit;
ScrollBox2: TScrollBox;
Edit2: TEdit;
ScrollBox3: TScrollBox;
Edit3: TEdit;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
FOldProc: TWndMethod;
procedure NewProc(var msg: TMessage);
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
begin
FoldProc := Scrollbox3.WindowProc;
Scrollbox3.WindowProc := NewProc;
end;
procedure TForm1.NewProc(var msg: TMessage);
var
oldpos, newpos: Integer;
begin
case msg.Msg of
WM_VSCROLL:
begin
oldpos := scrollbox3.VertScrollBar.Position;
FoldProc(msg);
newpos := scrollbox3.VertScrollBar.Position;
if oldpos <> newpos then
begin
scrollbox1.ScrollBy(0, oldpos - newpos);
scrollbox2.ScrollBy(0, oldpos - newpos);
end;
end;
WM_HSCROLL:
begin
oldpos := scrollbox3.HorzScrollBar.Position;
FoldProc(msg);
newpos := scrollbox3.HorzScrollBar.Position;
if oldpos <> newpos then
begin
scrollbox1.ScrollBy(oldpos - newpos, 0);
scrollbox2.ScrollBy(oldpos - newpos, 0);
end;
end
else
FoldProc(msg);
end;
end;
end.
Feliratkozás:
Megjegyzések küldése (Atom)
Nincsenek megjegyzések:
Megjegyzés küldése