代码之家  ›  专栏  ›  技术社区  ›  Mike Torrettinni

如何同步两个具有不同高度的TVirtualStringTree控件的滚动?

  •  1
  • Mike Torrettinni  · 技术社区  · 10 年前

    我有两个TVirtualStringTree(VST)控件,一个在另一个上面。TSplitter介于两者之间。滚动第一个VST2/1时,我使用VST1/2的OnScroll滚动另一个VST2/2:

    enter image description here

        procedure TForm1.VST1Scroll(Sender: TBaseVirtualTree; DeltaX, DeltaY: Integer);
        begin
          VST2.OffsetY:=VST1.OffsetY;
        end;
    
        procedure TForm1.VST2Scroll(Sender: TBaseVirtualTree; DeltaX, DeltaY: Integer);
        begin
          VST1.OffsetY:=VST2.OffsetY;
        end;
    

    使用滚动条上下滚动,效果很好。但前提是两者尺寸相同。问题是,当高度不同时,VST1滚动到最后,VST2仍有很多要走,反之亦然,这取决于哪个更高/更小。

    我尝试了许多偏移Y*高度百分比的组合……不同的计算,但即使高度不同,也无法同步滚动。

    例如,如果VST1.Height=100和VST。高度=200,则VST1上的每次滚动都应滚动VST2 2*OffsetY,以匹配它们并同时滚动到底部。嗯,这效果不好。

    它们都具有相同的NodeCount(在所附示例20中,但可能有1000个)。

    问题:如何计算一个VST中的每个滚动应滚动多少以同步另一个?或者,当高度不同时,有没有比同步两个VST的滚动更简单的方法

    这是。pas

    unit Unit1;
    
    interface
    
    uses
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
      Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, VirtualTrees;
    
    type
      TForm1 = class(TForm)
        VST1: TVirtualStringTree;
        VST2: TVirtualStringTree;
        Splitter1: TSplitter;
        procedure FormCreate(Sender: TObject);
        procedure VST1GetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
          Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
        procedure VST2GetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
          Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
        procedure VST1Scroll(Sender: TBaseVirtualTree; DeltaX, DeltaY: Integer);
        procedure VST2Scroll(Sender: TBaseVirtualTree; DeltaX, DeltaY: Integer);
      private
        { Private declarations }
      public
        { Public declarations }
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.dfm}
    
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      VST1.RootNodeCount := 20;
      VST2.RootNodeCount := 20;
    end;
    
    procedure TForm1.VST1GetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
      Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
    begin
      CellText:=IntToStr(Node.Index+1);
    end;
    
    procedure TForm1.VST1Scroll(Sender: TBaseVirtualTree; DeltaX, DeltaY: Integer);
    begin
      VST2.OffsetY:=VST1.OffsetY;
    end;
    
    procedure TForm1.VST2GetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
      Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
    begin
      CellText:=IntToStr(Node.Index+1);
    end;
    
    procedure TForm1.VST2Scroll(Sender: TBaseVirtualTree; DeltaX, DeltaY: Integer);
    begin
      VST1.OffsetY:=VST2.OffsetY;
    end;
    
    end.
    

    这是.dfm:

    object Form1: TForm1
      Left = 0
      Top = 0
      Caption = 'Form1'
      ClientHeight = 337
      ClientWidth = 635
      Color = clBtnFace
      Font.Charset = DEFAULT_CHARSET
      Font.Color = clWindowText
      Font.Height = -11
      Font.Name = 'Tahoma'
      Font.Style = []
      OldCreateOrder = False
      OnCreate = FormCreate
      PixelsPerInch = 96
      TextHeight = 13
      object Splitter1: TSplitter
        Left = 0
        Top = 100
        Width = 635
        Height = 3
        Cursor = crVSplit
        Align = alTop
        ExplicitWidth = 237
      end
      object VST1: TVirtualStringTree
        Left = 0
        Top = 0
        Width = 635
        Height = 100
        Align = alTop
        Header.AutoSizeIndex = 0
        Header.Font.Charset = DEFAULT_CHARSET
        Header.Font.Color = clWindowText
        Header.Font.Height = -11
        Header.Font.Name = 'Tahoma'
        Header.Font.Style = []
        Header.MainColumn = -1
        TabOrder = 0
        OnGetText = VST1GetText
        OnScroll = VST1Scroll
        Columns = <>
      end
      object VST2: TVirtualStringTree
        Left = 0
        Top = 103
        Width = 635
        Height = 234
        Align = alClient
        Header.AutoSizeIndex = 0
        Header.Font.Charset = DEFAULT_CHARSET
        Header.Font.Color = clWindowText
        Header.Font.Height = -11
        Header.Font.Name = 'Tahoma'
        Header.Font.Style = []
        Header.MainColumn = -1
        TabOrder = 1
        OnGetText = VST2GetText
        OnScroll = VST2Scroll
        Columns = <>
      end
    end
    
    2 回复  |  直到 10 年前
        1
  •  2
  •   kobik    10 年前

    VST具有受保护的属性 RangeY 它包含整个滚动范围,是解决方案的关键。

    所以 ClientHeight - RangeY =最大负值 OffsetY 在VST中。

    代码可能如下:

    type
      TForm1 = class(TForm)   
      ...
      private
        FScrolling: boolean;
        procedure SyncScroll(Sender, Target: TBaseVirtualTree);
      end;
    
    ...
    
    type
      TCustomVirtualStringTreeAccess = class(TCustomVirtualStringTree);
    
    procedure TForm1.SyncScroll(Sender, Target: TBaseVirtualTree);
    var
      SenderMaxOffsetY, TargetMaxOffsetY: Integer;
      DY: Extended;
    begin
      if FScrolling then Exit; // Avoid reentrancy from Target
      SenderMaxOffsetY := Sender.ClientHeight - Integer(TCustomVirtualStringTreeAccess(Sender).RangeY);
      TargetMaxOffsetY := Target.ClientHeight - Integer(TCustomVirtualStringTreeAccess(Target).RangeY);
      if SenderMaxOffsetY = 0 then Exit;
      DY := Sender.OffsetY / SenderMaxOffsetY;
      FScrolling := True;
      try
        Target.OffsetY := Round(TargetMaxOffsetY * DY);
      finally
        FScrolling := False;
      end;
    end;
    
    procedure TForm1.VST1Scroll(Sender: TBaseVirtualTree; DeltaX, DeltaY: Integer);
    begin
      SyncScroll(Sender, VST2);
    end;
    
    procedure TForm1.VST2Scroll(Sender: TBaseVirtualTree; DeltaX, DeltaY: Integer);
    begin
      SyncScroll(Sender, VST1);
    end;
    
        2
  •  1
  •   ain    10 年前

    如何同步顶部节点,而不是尝试保持两个树视图的像素完美同步?我看到VT有一个 TopNode 属性,所以我将尝试如下:

    • VT初始化后,保存树的顶部节点;
    • 在里面 OnScroll 事件检查当前顶部节点是什么-如果它已更改,则:
      • 记住树的新顶部节点;
      • 通知必须更新其TopNode的另一棵树;

    既然你说两棵树都有相同数量的节点,我假设它们显示的数据相同,所以可以将两棵树中的节点标识为“相同”(它们表示相同的数据)。