You are right, TTreeView
should have this, but it doesn't, and I don't see a good reason. However, here are some thoughts to take into account:
The data structure used in the TTreeView
doesn't directly support counting direct children or accessing them by index, because it is a linked list where each node links to its parent, its next and previous sibling, and its first child.
For your convenience, the TTreeNode
object is able to give you what you want, but for that it has to loop through the chain and count.
That also means, accessing all children in a for-loop is anyway not a good idea, like in the recursive function you mentioned - it would unnecessarily be a loop in a loop.
Instead, directly go through the chain using TreeView.Items.GetFirstNode
(or MyParentNode.getFirstChild
) and then a while loop with Node:= Node.getNextSibling
(that also works very well for a recursive function).
Suggestion: look at the implementation in Vcl.ComCtrls. From there, you could also adapt the two most elegant functions you ask for, in case you still need it :)
type
TTreeViewClassHelper = class helper for TTreeView
function GetRootCount: Integer;
function GetRootItem(Index: Integer): TTreeNode;
end;
function TTreeViewClassHelper.GetRootCount: Integer;
var
Node: TTreeNode;
begin
Result:= 0;
Node:= Items.GetFirstNode;
while Assigned(Node) do begin
Inc(Result);
Node:= Node.getNextSibling;
end;
end;
function TTreeViewClassHelper.GetRootItem(Index: Integer): TTreeNode;
begin
Result:= Items.GetFirstNode;
while Assigned(Node) and (Index > 0) do begin
Result:= Result.getNextSibling;
Dec(Index);
end;
end;
And just to demonstrate how you should not do it ;-)
for I:= 0 to TreeView.GetRootCount - 1 do
with TreeView.GetRootItem(I) do
Memo.Lines.Add(string.Join(#9, [AbsoluteIndex, Index, Text]));