3

I am not yet very experienced with the TVirtualStringTree component, therefore maybe I overlooked something trivial.

My app gathers File Information into a record (FileName, Path, Size) and displays the data in a Virtual String Tree.

Now when there are lots of Nodes (200K+) I experience a heavy slow down, the whole Tree basically lags. I am aware that the memory footprint is quite large with just the record data alone, but I found out that the lag is caused by the OnGetText method of the VST. Hereby it doesn't matter if the method reads actual data or sets the CellText to an static string (e.g. CellText := 'Test';) the slow down is significant. If I exit OnGetText without setting CellText, it works fine - even with as much as 1,000,000 Nodes in my Tree. Also, If I collapse the Tree (FullCollapse) hiding this way 90% of my Nodes, OnGetText behaves ok as well or at least much better.

As far as I understand it, the OnGetText is only called for actually visible On Screen Nodes, therefore I don't get why this is such an issue with large amounts of Nodes in the Tree.

Anybody has any hints for me to point me in a direction?

EDIT:

Delphi Version: D2010 VST Version: 4.8.6

My code in its simplest test form is basically as follows:

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;

If I set CellText, it lags, if I exit, it doesn't. Strange enough, it gets worse the further I scroll down.

Here's what's assigned as 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;

I noticed, that expanding / collapsing and re-expanding somehow seems to improve the situation, but it's beyond me to tell why this could actually have any impact.

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
BlackOut
  • 81
  • 1
  • 5
  • You will get better answers if you show your code, at least the code you have in the OnGetText handler. Btw, I have only ever experienced slow downs, when I did something "stupid" in a method that gets called on almost every mouse move... – Marjan Venema Jul 28 '10 at 17:09
  • Hi BlackOut! Welcome to StackOverflow. That's a pretty good first question. I don't know much about VirtualStringTree, so I won't try to post a real answer, but it sounds like your performance is degrading linearly as the number of open nodes increases. That makes it look like setting CellText has to scan through all the nodes of the tree for some reason. Try looking in the code and see if you can find some sort of linear search going on when you change CellText. – Mason Wheeler Jul 28 '10 at 17:14
  • My code is pretty basic, as I have removed each part that could complicate things for debugging purposes. Meanwhile, I think I might be onto something as it seems once I collapse and expand the tree again, it works ok. I will give it some more tests and update my post tomorrow or add an answer if I happen to figure out what is responsible. – BlackOut Jul 28 '10 at 23:54
  • Are you having autosort ON by any chance? – r4w8173 Jul 31 '10 at 06:56
  • TreeOptions.AutoOptions.toAutoSort := False – BlackOut Aug 14 '10 at 08:00

4 Answers4

3

If any of your columns are auto-sized, then the control needs to know the widths of all the nodes' values in order to determine the maximum.

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
1

You did not say which version of Delphi you are using. In versions prior to D2009, TVirtualTreeView uses the WideString string type, which is inherently slow in general as it does not have the reference-counting, copy-on-write semantics that AnsiString has, so try to minimize your string operations as much as possible. In D2009 and later, TVirtualTreeView uses the newer UnicodeString string type instead of WideString.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Yes, I should have provided that info. I'm using Delphi 2010 with Virtual String Tree Version 4.8.6 – BlackOut Jul 28 '10 at 23:48
1

Strange, I thought it was the whole design of VST to only load cellnodes for the nodes in the active view, not the entire tree. Are you sure it isn't some other factor in the code that you don't show, like doing a fileexists or so for every node?

Marco van de Voort
  • 25,628
  • 5
  • 56
  • 89
1

Problem solved. It turns out, there might have been a complication while deleting nodes. Instead of deleting all children of a parent node, only the parent node has been removed. I expected the childnodes to be removed automatically as well, but when I changed the code to first delete children then the parent node, the lagging vanished. Now I can load a million file names to the tree without lag.

BlackOut
  • 81
  • 1
  • 5