3

我对 TVirtualStringTree 组件还不是很有经验,因此也许我忽略了一些微不足道的事情。

我的应用程序将文件信息收集到记录(文件名、路径、大小)中,并在虚拟字符串树中显示数据。

现在,当有很多节点(200K+)时,我经历了严重的减速,整个树基本上都滞后了。我知道仅记录数据占用的内存就很大,但我发现延迟是由 VST 的 OnGetText 方法引起的。因此,该方法是否读取实际数据或将 CellText 设置为静态字符串(例如 CellText := 'Test';)并不重要,减速很重要。如果我在不设置 CellText 的情况下退出 OnGetText,它可以正常工作 - 即使我的树中有多达 1,000,000 个节点。此外,如果我折叠树(FullCollapse)以这种方式隐藏 90% 的节点,OnGetText 的行为也可以,或者至少要好得多。

据我了解,仅在实际可见的屏幕节点上调用 OnGetText,因此我不明白为什么树中有大量节点会出现这样的问题。

有人有任何提示让我指出一个方向吗?

编辑:

德尔福版本:D2010 VST 版本:4.8.6

我最简单的测试形式的代码基本上如下:

var
  SkipGetText : boolean;

procedure TXForm.VSTGetText(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
begin
  if SkipGetText then exit;
  CellText := 'TEST';
  // actual code commented out to reduce complications
end;

如果我设置 CellText,它会滞后,如果我退出,它不会。奇怪的是,我越往下滚动,情况就越糟。

这是分配为 NodeData 的内容:

type
  PVSData = ^Fi;
  Fi = Packed Record
    Name, Dir, Ext: String;
    Size: Int64;
  end;

procedure TXForm.AddFile( const RootFolder:string; const SR: TSearchRec );
var
  FileInfo: PVSData;
  FileSize: Int64;
  Node: PVirtualNode;
begin
  Node          := VST.AddChild(nil);
  INC(AllFiles);
  FileInfo      := VST.GetNodeData(Node);
  FileInfo^.Name := SR.Name;
  FileInfo^.Dir  := RootFolder;

  Int64Rec(FileSize).Hi := SR.FindData.nFileSizeHigh;
  Int64Rec(FileSize).Lo := SR.FindData.nFileSizeLow;
  FileInfo^.Size         := FileSize;
end;

procedure TXForm.VSTPaintText(Sender: TBaseVirtualTree;
const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType);
begin
  if SkipPaintText then exit;

  case ListView.GetNodeLevel(Node) of
    0: TargetCanvas.Font.Color := Color1;
    else TargetCanvas.Font.Color := Color2;
  end;
end;

procedure TXForm.VSTBeforeCellPaint(Sender: TBaseVirtualTree;
  TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
  CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect);
begin
  case ListView.GetNodeLevel(Node) of
    0: TargetCanvas.Font.Color := Color1;
    else TargetCanvas.Font.Color := Color2;
  end;
end;

我注意到,扩展/折叠和重新扩展似乎以某种方式改善了这种情况,但我无法说出为什么这实际上会产生任何影响。

4

4 回答 4

3

如果您的任何列是自动调整大小的,则控件需要知道所有节点值的宽度才能确定最大值。

于 2010-07-28T20:01:45.410 回答
1

您没有说您使用的是哪个版本的 Delphi。在 D2009 之前的版本中,TVirtualTreeView使用WideString字符串类型,这通常本身就很慢,因为它没有引用计数、写时复制语义AnsiString,因此请尽量减少字符串操作。在 D2009 及更高版本中,TVirtualTreeView使用较新的UnicodeString字符串类型而不是WideString.

于 2010-07-28T19:34:39.663 回答
1

奇怪,我认为 VST 的整个设计是只为活动视图中的节点加载单元节点,而不是整个树。你确定它不是你没有显示的代码中的其他因素,比如为每个节点做一个文件存在吗?

于 2010-07-29T03:37:07.643 回答
1

问题解决了。事实证明,删除节点时可能会出现复杂情况。不是删除父节点的所有子节点,而是仅删除父节点。我希望子节点也会自动删除,但是当我将代码更改为先删除子节点然后删除父节点时,滞后消失了。现在我可以毫无延迟地将一百万个文件名加载到树中。

于 2010-08-14T07:58:23.937 回答