如何获取TVirtualStringTree中显示的节点个数?

How to get a number of displayed nodes in TVirtualStringTree?

我需要在 TVirtualStringTree 中显示一个长数据库 table(例如 50000 条记录)。为了缩短查询执行时间,我将记录数限制为仅显示在树中的记录数。处理 OnGetText 的代码片段如下。问题是 VisibleCount returns 50000 而不是 20-30 破坏了这种方法。有没有办法正确地做到这一点?

procedure TContactsFrame.vstContactsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; 
  Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
begin
  if vstContacts.GetNodeLevel(Node) = 0 then
    CellText := 'Group'
  else if vstContacts.GetNodeLevel(Node) = 1 then
  begin
    if Contacts[Node.Index].Index = -1 then
    begin
      // getting DB table values of visible records only
      GetContacts(Node.Index + 1, Node.Index + 1 + vstContacts.VisibleCount, Contacts);
    end;
    CellText := Contacts[Node.Index].Name;
  end;
end;

要查找显示的节点数,您需要编写自己的函数,但在这种情况下,使用 TopNodeBottomNode 获取第一个和最后一个显示的节点应该就足够了或者 GetFirstGetLast 如果它们不存在。

procedure TContactsFrame.vstContactsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; 
  Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
var
  lTopNode, lBottomNode : PVirtualNode;
begin
  case vstContacts.GetNodeLevel(Node) of
    0 : CellText := 'Group'
    1 : begin
          if Contacts[Node.Index].Index = -1 then
          begin
            // getting DB table values of visible records only
            lTopNode := vstContacts.TopNode;
            if not Assigned(lTopNode) then
              lTopNode := vstContacts.GetFirst;
            lBottomNode := vstContacts.BottomNode;
            if not Assigned(lBottomNode) then
              lBottomNode := vstContacts.GetLast;
            GetContacts(lTopNode.Index + 1, lBottomNode.Index + 1, Contacts);
          end;
          CellText := Contacts[Node.Index].Name;
        end;
  end;
end;

但是我不得不说,这似乎不是最有效的解决方案,因为您将 运行 在不经意地滚动树的同时进行数以千计的查询。如果有的话,我会增加检索到的联系人数量,这样您就不需要 运行 如此频繁地进行新查询。

VisibleCount 为您提供设置了 vsVisible 标志的节点数(可见意味着未隐藏)。

要枚举当前显示在树视图中的节点,您可以使用 TopNodeBottomNode 类似的方式:

var
  Run, LastNode: PVirtualNode;
begin
  LastNode := Treeview.GetNextVisible(Treeview.BottomNode);
  Run := Treeview.TopNode;

  while Assigned(Run) do
  begin
    // your processing here

    Run := Treeview.GetNextVisible(Run);
    if Run = LastNode then
      Break;
  end;
end;