delphitvirtualstringtree

How to get a number of displayed nodes in TVirtualStringTree?


I need to show a long db table in the TVirtualStringTree (e.g. 50000 records). To lower query execution time I limit the number of records with only those that are actually displayed in the tree. The code snippet of handling OnGetText is below. The problem is that VisibleCount returns 50000 instead of 20-30 which ruins this approach. Is there a way to do it properly?

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;

Solution

  • To find the number of displayed nodes you need to write your own function, but in this case, it should be enough to get the first and the last displayed node using TopNode and BottomNode or GetFirst and GetLast if they don't exist.

    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;
    

    However I have to say that this doesn't seem to be the most effective solution, because you will run thousands of queries while casually scrolling the tree. If anything, I would multiply the number of retrieved contacts, so you don't need to run new queries so often.