Note to self: Do not enumerate on TTreeNode.Item, it’s highly inefficient.
Consider this code:
procedure SelectFocusedControl(_ActCtrl: TWinControl; _Parent: TTreeNode);
var
j: Integer;
CtrlItem: TTreeNode;
begin
for j := 0 to _Parent.Count - 1 do begin
CtrlItem := _Parent.Item[j];
if CtrlItem.Data = _ActCtrl then begin
CtrlItem.Selected := true;
break;
end else
SelectFocusedControl(_ActCtrl, CtrlItem);
end;
end;
This code is from my Delphi IDE Explorer expert (a bit simplified for readability).
It does something very simple: It goes through all child nodes of the given Parent TTreeNode and looks for one whose Data property matches the given ActCrl parameter. This node then gets selected.
I always wondered why this takes so long until I had a look at the implementation of TTreeNode.GetItem today:
function TTreeNode.GetItem(Index: Integer): TTreeNode;
begin
Result := GetFirstChild;
while (Result <> nil) and (Index > 0) do
begin
Result := GetNextChild(Result);
Dec(Index);
end;
if Result = nil then TreeViewError(Format(SListIndexError, [Index]));
end;
This is the current implementation in Delphi 10 Seattle.
As you can see, in order to get the Index’ed item, it enumerates through all child items counting them until reaching the given Index. And since my code calls it for each item, this is highly inefficient.
Now, consider this alternative code:
procedure SelectFocusedControl(_ActCtrl: TWinControl; _Parent: TTreeNode);
var
CtrlItem: TTreeNode;
begin
CtrlItem := _Parent.getFirstChild;
while Assigned(CtrlItem) do begin
if CtrlItem.Data = _ActCtrl then begin
CtrlItem.Selected := true;
break;
end else
SelectFocusedControl(_ActCtrl, CtrlItem);
CtrlItem := CtrlItem.getNextSibling;
end;
end;
This uses basically the same code as TTreeNode.GetItem, so it only loops through the items once. Much faster.
EDIT:
I deleted the rest of this post regarding TTreeNodesEnumerator. It was clearly wrong.