加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

delphi – 如何同步滚动2个TTreeviews?

发布时间:2020-12-15 04:30:12 所属栏目:大数据 来源:网络整理
导读:我有2个TTreeviews.它们都具有相同数量的项目. 我希望能够同步他们的滚动条…如果我移动其中一个,另一个移动也… 对于水平,它按预期工作… 对于垂直方向,如果我使用滚动条的箭头,它会起作用,但如果我拖动拇指或使用鼠标滚轮则不会… 这是我写的一个例子来说
我有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;

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读