VirtualStringTree - how to get node from absolute index?

1.5k Views Asked by At

Lets say i'm using a VirtualStringTree in virtual mode.

I want to indicate that the tree has some nodes:

VirtualStringTree1.RootNodeCount := 999983;

And since this tree is in virtual mode:

  • all data management happens in the application
  • and on demand

Now sometime later i want to mark a node as Selected

Something has happened in my underlying TList (e.g. at index 797,977) that would cause one of the nodes (if it's visible) to need to change its Selected status.

Since everything in a virtual tree is based on Node.Index, ideally there would be a way to indicate that an index is selected:

VirtualStringTree1.RootNodeCount := 999983;
VirtualStringTree1.Selected[797977] := True; //indicate that node at index 797977 is now selected

But the tree doesn't have an overload to set selection by index.

The only method to alter a node's selected state is to:

  • have a PVirtualNode
  • pass that to VirtualStringTree1.Selected[node] := True;

How can i mark a node as selected, when i don't have the node?

Windows ListView solution

A Windows ListView control in virtual mode solves it pretty simply.

  • everything is based equivalently on Node.Index
  • and the control uses callbacks to ask the application on demand for display information

So you are given a LVN_GETDISPINFO callback. And that is when you populate the callback structure, and give the tree the information it is asking for on demand:

  • Text
  • State (e.g. Selected)
  • ImageIndex
  • Indent

But for simplicity you can think of it as:

procedure TForm1.VirtualStringTree1GetSelected(Sender: TBaseVirtualTree; Node: PVirtualNode; var Result: Boolean);
begin
   Result := True; //yes, this node is selected
end;

And so the way i would mark an item in the tree as Selected is i would call:

ListView1.Invalidate;

If the item #797,977 is currently on screen: it will redraw during the next paint cycle as selected.

What's the Virtual Treeivew equivalent of marking a node as Selected when all you have is a virtual-mode index?

Hack

function GetNodeByIndex(Tree: TVirtualStringTree; Index: Integer): PVirtualNode;
var
   node: PVirtualNode;
begin
   Result := nil;

   node := Tree.GetFirstChildNoInit(nil);
   while Assigned(node) do
   begin
      if node.Index = Index then
      begin
         Result := node; 
         Exit;
      end;
      node := Tree.GetNextNoInit(node);
   end;
end;

But traversing a linked list of 797,977 items in order to get node n is very bad. It's on the order of O(n) bad.

0

There are 0 best solutions below