Virtual mode, also called “on-demand node creation,” allows you to create child nodes only when a parent node is expanded for the first time. This approach dramatically improves performance when working with large tree hierarchies by deferring node creation until absolutely necessary.
Virtual mode is ideal for:
Large datasets (thousands of nodes)
Database-driven trees
File system browsers
Any hierarchical data where children are expensive to load
Set ShowCross to scAlways so expand/collapse icons appear
Listen to the OnExpandingCollapsing event
Create child nodes dynamically when a node is first expanded
1
Initialize Root Nodes
Create only the top-level nodes when your tree loads:
// Add first level "Root" example nodes onlyfor t := 1 to 10 do Tree1.Add('Root ' + IntToStr(t));
2
Configure ShowCross Property
Set nodes to always show the expand/collapse box, even when they have no children yet:
// Important: Set ShowCross property to scAlways// so the +/- box is always visiblefor t := 0 to Tree1.Roots.Count-1 do Tree1.Roots[t].ShowCross := scAlways;
Without setting ShowCross := scAlways, users won’t see any indication that nodes can be expanded.
3
Implement OnExpandingCollapsing Event
Create children only when a node is expanded for the first time:
procedure TForm1.Tree1ExpandingCollapsing( Sender: TTreeNodeShape; var Expand: Boolean);var t: Integer; NumChildren: Integer;begin if Expand then if Sender.Children.Count = 0 then // First time expanded! begin // Add children nodes NumChildren := 1 + Random(5); // How many? (random example) for t := 1 to NumChildren do Sender.AddChild('Child ' + IntToStr(t)); // Set ShowCross for children too for t := 1 to NumChildren do Sender.Children[t-1].ShowCross := scAlways; end;end;
Here’s a full working example from the TeeTree source:
unit CreateOnDemand;interfaceuses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, TeeTree, ExtCtrls, StdCtrls;type TCreateOnDemandForm = class(TForm) Tree1: TTree; procedure FormCreate(Sender: TObject); procedure Tree1ExpandingCollapsing(Sender: TTreeNodeShape; var Expand: Boolean); end;implementationprocedure TCreateOnDemandForm.FormCreate(Sender: TObject);var t: Integer;begin // Add first level "Root" example nodes only for t := 1 to 10 do Tree1.Add('Root ' + IntToStr(t)); // Set nodes ShowCross property to "scAlways" for t := 0 to Tree1.Roots.Count-1 do Tree1.Roots[t].ShowCross := scAlways; // Remove border Tree1.GlobalFormat.Border.Visible := False;end;procedure TCreateOnDemandForm.Tree1ExpandingCollapsing( Sender: TTreeNodeShape; var Expand: Boolean);var t: Integer; NumChildren: Integer;begin if Expand then if Sender.Children.Count = 0 then // Very first time expanded! begin // Add children nodes NumChildren := 1 + Random(5); for t := 1 to NumChildren do Sender.AddChild('Child ' + IntToStr(t)); // Set ShowCross for children for t := 1 to NumChildren do Sender.Children[t-1].ShowCross := scAlways; end;end;end.
Virtual mode is perfect for database-driven trees:
procedure TForm1.TreeExpandingCollapsing( Sender: TTreeNodeShape; var Expand: Boolean);var Query: TQuery; ParentID: Integer;begin if Expand and (Sender.Children.Count = 0) then begin ParentID := Integer(Sender.Data); // Store DB ID in node Data Query := TQuery.Create(nil); try Query.SQL.Text := 'SELECT * FROM Items WHERE ParentID = :PID'; Query.Params.ParamByName('PID').AsInteger := ParentID; Query.Open; while not Query.Eof do begin with Sender.AddChild(Query.FieldByName('Name').AsString) do begin Data := Pointer(Query.FieldByName('ID').AsInteger); ShowCross := scAlways; // May have children end; Query.Next; end; finally Query.Free; end; end;end;
// Creates all 10,000 nodes immediatelyfor i := 1 to 100 dobegin Root := Tree1.Add('Root ' + IntToStr(i)); for j := 1 to 100 do Root.AddChild('Child ' + IntToStr(j));end;// Result: Slow startup, high memory usage
Creating nodes on-demand:
// Creates only 100 root nodes initiallyfor i := 1 to 100 dobegin Root := Tree1.Add('Root ' + IntToStr(i)); Root.ShowCross := scAlways;end;// Children created only when expanded// Result: Fast startup, low memory usage
You can prevent a node from expanding by setting the Expand parameter to False:
procedure TForm1.TreeExpandingCollapsing( Sender: TTreeNodeShape; var Expand: Boolean);begin if Expand then begin // Check if user has permission if not UserHasPermission(Sender) then begin ShowMessage('Access denied'); Expand := False; // Cancel the expansion Exit; end; // Create children... end;end;