我有2个TTreeviews.它们都具有相同数量的项目.
我希望能够同步他们的滚动条…如果我移动其中一个,另一个移动也…
我希望能够同步他们的滚动条…如果我移动其中一个,另一个移动也…
对于水平,它按预期工作…
对于垂直方向,如果我使用滚动条的箭头,它会起作用,但如果我拖动拇指或使用鼠标滚轮则不会…
这是我写的一个例子来说明我的问题:
unit main; interface uses Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms,Dialogs,ComCtrls,StrUtils; type TForm1 = class(TForm) tv1: TTreeView; tv2: TTreeView; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private { Private declarations } originalTv1WindowProc : TWndMethod; originalTv2WindowProc : TWndMethod; procedure Tv1WindowProc (var Msg : TMessage); procedure Tv2WindowProc (var Msg : TMessage); public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.FormCreate(Sender: TObject); var i: Integer; begin for i := 0 to 10 do begin tv1.Items.AddChild(nil,DupeString('A',20) + IntToStr(i)); tv2.Items.AddChild(nil,DupeString('B',20) + IntToStr(i)); end; originalTv1WindowProc := tv1.WindowProc; tv1.WindowProc := Tv1WindowProc; originalTv2WindowProc := tv2.WindowProc; tv2.WindowProc := Tv2WindowProc; end; procedure TForm1.FormDestroy(Sender: TObject); begin tv1.WindowProc := originalTv1WindowProc; tv2.WindowProc := originalTv2WindowProc; originalTv1WindowProc := nil; originalTv2WindowProc := nil; end; procedure TForm1.Tv1WindowProc(var Msg: TMessage); begin originalTv1WindowProc(Msg); if ((Msg.Msg = WM_VSCROLL) or (Msg.Msg = WM_HSCROLL) or (Msg.msg = WM_Mousewheel)) then begin // tv2.Perform(Msg.Msg,Msg.wparam,Msg.lparam); originalTv2WindowProc(Msg); end; end; procedure TForm1.Tv2WindowProc(var Msg: TMessage); begin originalTv2WindowProc(Msg); if ((Msg.Msg = WM_VSCROLL) or (Msg.Msg = WM_HSCROLL) or (Msg.msg = WM_Mousewheel)) then begin // tv1.Perform(Msg.Msg,Msg.lparam); originalTv1WindowProc(Msg); end; end; end.
DFM:
object Form1: TForm1 Left = 0 Top = 0 Caption = 'Form1' ClientHeight = 113 ClientWidth = 274 Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'Tahoma' Font.Style = [] OldCreateOrder = False OnCreate = FormCreate OnDestroy = FormDestroy PixelsPerInch = 96 TextHeight = 13 object tv1: TTreeView Left = 8 Top = 8 Width = 121 Height = 97 Indent = 19 TabOrder = 0 end object tv2: TTreeView Left = 144 Top = 8 Width = 121 Height = 97 Indent = 19 TabOrder = 1 end end
我也试过从TTreeview创建一个子类,但没有成功(相同的行为)……
我尝试使用TMemo,它按预期工作…
我错过了什么?
干杯,
W.
解决方法
首先,一个有趣的测试:取消选中项目选项中的“启用运行时主题”,您将看到两个树视图将同步滚动.这向我们展示了在不同版本的comctl32.dll中以不同方式实现树视图控件的默认窗口过程.看来,在滚动垂直时,comctl32 v6中的实现特别不同.
无论如何,似乎仅对于垂直滚动,控件查找拇指位置,然后相应地调整窗口内容.当您将WM_VSCROLL路由到相邻的树视图时,它会查看其拇指的位置,并且当它没有被更改时,决定无所事事(我们只更改了我们拖动的拇指位置).
因此,要使其工作,请在发送WM_VSCROLL之前调整树视图的拇指位置. tv1的修改过程如下所示:
procedure TForm1.Tv1WindowProc(var Msg: TMessage); begin originalTv1WindowProc(Msg); if Msg.Msg = WM_VSCROLL then begin if Msg.WParamLo = SB_THUMBTRACK then SetScrollPos(tv2.Handle,SB_VERT,Msg.WParamHi,False); end; if ((Msg.Msg = WM_VSCROLL) or (Msg.Msg = WM_HSCROLL) or (Msg.msg = WM_Mousewheel)) then begin // tv2.Perform(Msg.Msg,Msg.lparam); originalTv2WindowProc(Msg); end; end;