Delphi - 大量节点的虚拟字符串树慢GetText方法

时间:2010-07-28 17:06:50

标签: delphi virtualtreeview

我对TVirtualStringTree组件还不是很熟悉,因此我可能忽略了一些微不足道的事情。

我的应用将文件信息收集到一条记录(FileName,Path,Size)中,并在虚拟字符串树中显示数据。

现在当有很多节点(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 个答案:

答案 0 :(得分:3)

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

答案 1 :(得分:1)

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

答案 2 :(得分:1)

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

答案 3 :(得分:1)

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