VirtualStringTree - 如何从绝对索引获取节点?

Ian*_*oyd 5 delphi virtualtreeview

假设我在虚拟模式下使用VirtualStringTree

我想指出树有一些节点:

VirtualStringTree1.RootNodeCount := 999983;
Run Code Online (Sandbox Code Playgroud)

由于该树处于虚拟模式:

  • 所有数据管理都发生在应用程序中
  • 并按需

现在稍后我想将一个节点标记为“选定”

我的底层TList中发生了一些事情(例如在索引处797,977),这将导致节点之一(如果它可见)需要更改其Selected状态。

由于虚拟树中的所有内容都基于Node.Index,因此理想情况下应该有一种方法来指示选择了索引:

VirtualStringTree1.RootNodeCount := 999983;
VirtualStringTree1.Selected[797977] := True; //indicate that node at index 797977 is now selected
Run Code Online (Sandbox Code Playgroud)

但是树没有重载来按索引设置选择。

改变节点选定状态的唯一方法是:

  • 一个PVirtualNode
  • 将其传递给VirtualStringTree1.Selected[node] := True;

当我没有节点时,如何将节点标记为选中?

Windows 列表视图解决方案

虚拟模式下的Windows ListView控件可以非常简单地解决这个问题。

  • 一切都同等地基于Node.Index
  • 并且控件使用回调来按需应用程序询问显示信息

所以你会得到一个LVN_GETDISPINFO回调。那就是当您填充回调结构,并根据需要向树提供它所要求的信息时:

  • 文本
  • 状态(例如选定)
  • 图像索引
  • 缩进

但为了简单起见,您可以将其视为:

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

因此,我将树中的项目标记为“已选择”的方式是:

ListView1.Invalidate;
Run Code Online (Sandbox Code Playgroud)

如果项目#797,977当前在屏幕上:它将在所选的下一个绘制周期期间重绘。

当您拥有的只是虚拟模式索引时,将节点标记为“选定”的Virtual Treeivew等效项是什么?

黑客

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;
Run Code Online (Sandbox Code Playgroud)

但是遍历一个包含 797,977 项的链表来获取节点n是非常糟糕的。它的数量级是O(n) bad。