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.
I deleted the rest of this post regarding TTreeNodesEnumerator. It was clearly wrong.