Do not enumerate on TTreeNode.Item

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.