我有2个TVirtualStringTree(VST)控件,一个在另一个上面。在TSplitter之间。滚动第一个时,我使用OnScroll of VST1 / 2滚动另一个VST2 / 1:
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仍然有很多可用,反之亦然,取决于哪个更高/更小。
我尝试了多种OffsetY *高度百分比的组合...不同的计算但是即使高度不同也没有任何滚动同步。
例如,如果VST1.Height = 100且VST.Height = 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
答案 0 :(得分:2)
VST有一个受保护的属性RangeY
,它包含整个滚动范围,是解决方案的关键。
因此,ClientHeight - RangeY
= VST中的最大负数OffsetY
。
代码可能如下所示:
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;
答案 1 :(得分:1)
如何同步顶部节点而不是尝试将两个树视图保持在像素完美同步中?我看到VT有一个TopNode
属性,所以我会尝试这样的东西:
OnScroll
事件中检查当前顶级节点是什么 - 如果它已更改,则:
既然你说两棵树都有相同数量的节点,我假设它们显示相同的数据,因此可以在两棵树中将节点识别为“相同”(它们代表相同的数据)。