Delphi TVirtualStringTree和垂直卷轴工作不正常

Delphi TVirtualStringTree和垂直卷轴工作不正常,delphi,scroll,virtualtreeview,tvirtualstringtree,Delphi,Scroll,Virtualtreeview,Tvirtualstringtree,我已经学会了如何使用TVirtualStringTree,我发现它非常棒。我有一个自定义的非可视列表,名为PackedList,由另一个线程填充。我想在TVirtualStringTree中实时显示所有列表内容。因此,我在主窗体上设置了一个计时器,每500毫秒更新一次HexLog(即TVirtualStringTree)的RootNodeCount 我所有的数据都显示在VirtualStringTree上,我没有任何速度问题,非常好。但是垂直滚动条有一个问题。当我在控件上按Ctrl+End以跳转

我已经学会了如何使用TVirtualStringTree,我发现它非常棒。我有一个自定义的非可视列表,名为PackedList,由另一个线程填充。我想在TVirtualStringTree中实时显示所有列表内容。因此,我在主窗体上设置了一个计时器,每500毫秒更新一次HexLog(即TVirtualStringTree)的RootNodeCount

我所有的数据都显示在VirtualStringTree上,我没有任何速度问题,非常好。但是垂直滚动条有一个问题。当我在控件上按Ctrl+End以跳转到列表的末尾时,它位于中间的某个位置。类似地,当我将滚动条拖到末端时,它不会拖到末端。但是HexLog知道数据计数。为什么不跳到最后呢?如果我按几次Ctrl+END,它就会到达末尾

在计时器例程中,我想说HexLog通过代码跳转到列表的末尾。我如何才能做到这一点,以及如何处理垂直滚动条正确

procedure TMainForm.StatusUpdateTimerTimer(Sender: TObject);
begin
   if (FirpList.ComOperationCount > 0) and (PacketList.Items.Count <> FirpList.ComOperationCount) then
    begin
      HexLog.RootNodeCount := PacketList.Items.Count;
    end;
end;

procedure TMainForm.HexLogMeasureItem(Sender: TBaseVirtualTree;
  TargetCanvas: TCanvas; Node: PVirtualNode; var NodeHeight: Integer);
begin
  if Sender.MultiLine[Node] then
  begin
    TargetCanvas.Font := Sender.Font;
    NodeHeight := HexLog.ComputeNodeHeight(TargetCanvas, Node, 1, FirpList.ComOperations[Node^.Parent^.Index].DataAsHexString(FAppSettings.HexLogColumnCharWidth) + #13#10);
  end;
end;
程序TMainForm.StatusUpdateTimer(发送方:ToObject);
开始
如果(FirpList.ComOperationCount>0)和(PacketList.Items.Count FirpList.ComOperationCount),则
开始
HexLog.RootNodeCount:=PacketList.Items.Count;
结束;
结束;
程序TMainForm.HexLogMeasureItem(发送方:TBaseVirtualTree;
TargetCanvas:TCanvas;节点:PVirtualNode;变量NodeHeight:Integer);
开始
如果是Sender.MultiLine[Node],则
开始
TargetCanvas.Font:=发件人.Font;
NodeHeight:=HexLog.ComputeNodeHeight(TargetCanvas,Node,1,FirpList.ComOperations[Node^.Parent^.Index]。DataAsHexString(FAppSettings.HexLogColumnCharWidth)+#13#10);
结束;
结束;

TLama建议的回复工作不正常,请参见图片以了解解释:


有关详细的图像说明,请参见该链接:

要跳到树的末尾,请调用
ScrollIntoView(GetLast)

要滚动到特定节点,控件需要将所有先前节点的高度相加,以便确定适当的偏移

节点具有不同的高度。如果没有在某个位置初始化节点的实际高度,则控件将对任何未初始化的节点使用
DefaultNodeHeight
属性。看起来该高度比树中的任何实际节点高度都要短,因此该控件最终计算的偏移量比预期的要小,并在此处滚动,而不是在预期的位置滚动

确保您正在处理
OnMeasureItem
事件,并且在
Options.mischoptions
中设置了
toVariableNodeHeight
选项。如果不这样做,则控件将只为每个节点使用当前指定的高度,并为任何未初始化的节点使用默认高度


如果您手动分配
节点高度
,而不是将
设置为VariableNodeHeight
并在MeasureItem上处理

,则可以获得您在此报告的行为。嗨,Rob,我在MeasureItem上有处理程序来计算多行子项高度。未在MiscOptions上设置toVariableNodeHeight。我实现了这一点,现在ScrollIntoView()正确地跳到了末尾。但它会稍微向下滚动,大约需要2秒钟才能到达终点,这是不可接受的:/计算最后一个节点的偏移量,除了计算所有新节点的高度外,最主要的事情是如果节点位置缓存无效。在
GetDisplayRect
中设置断点,查看调用
ScrollIntoView
时是否处于
tsUseCache
状态。当缓存有效时,树可以更快地找到节点的位置,但更改节点数会使缓存无效。工作线程需要时间重新验证它。(FStates中的tsUseCache)GetDisplayRect()函数中的条件在调用ScrollIntoView()时返回false。我现在该怎么办?对于这个项目,我使用的是RichEdit控件,因为我面临速度问题,我将所有设计都改为使用VirtualStringTree。现在我又回到了同一点:/实际上,我很难理解为什么我需要计算整个消息的高度才能跳到列表的末尾。我只是想在数据事务处于活动状态时每隔500毫秒向用户显示最后一条消息。您需要所有节点的高度,因为控件需要知道要显示的偏移量。如果它不知道它的偏移量,则无法正确显示滚动条或正确向上滚动。使用探查器找出滚动操作的哪些部分花费的时间最多,然后看看是否可以减少在这些部分花费的时间。我这样做了。如果没有OnMeasureItem处理程序,ScrollIntoView()需要720ms。使用上面显示的OnMeasureItem处理程序需要1799ms。有没有一种方法可以强制VirtualStringTree在不滚动的情况下计算节点高度,以便所有节点在其状态下都有tsUseCache?