傳統做法用陣列或 TStringList 存節點代碼,索引易脫節、記憶體碎片化、釋放麻煩。TTreeNode.Data 與 TListItem.Data 為 Pointer,可直接指向記錄結構,效能與維護性雙贏。
type
TUnitNodeInfo = record
UnitCode: string; // 部門代碼(唯一鍵)
UnitName: string; // 部門名稱
Manager: string; // 擴充欄位:主管
// ... 其他業務欄位
end;
PUnitNodeInfo = ^TUnitNodeInfo;
procedure CreateUnitTree;
var
Node: TTreeNode;
Info: PUnitNodeInfo;
begin
// 假設已開啟 Query 並定位第一筆
while not Query.Eof do
begin
Node := TreeView1.Items.AddChild(nil, Query.FieldByName('UnitName').AsString);
Node.ImageIndex := 0; // 設定圖示
New(Info); // 配置記憶體
Info^.UnitCode := Query.FieldByName('UnitCode').AsString;
Info^.UnitName := Query.FieldByName('UnitName').AsString;
Info^.Manager := Query.FieldByName('Manager').AsString;
Node.Data := Info; // 綁定指標
Query.Next;
end;
end;
procedure TForm1.TreeView1Change(Sender: TObject; Node: TTreeNode);
var
Code: string;
begin
if Assigned(Node) and Assigned(Node.Data) then
begin
Code := PUnitNodeInfo(Node.Data)^.UnitCode;
// 以 Code 查詢人員列表、顯示詳情...
end;
end;
procedure TForm1.FreeTreeData;
var
i: Integer;
begin
for i := 0 to TreeView1.Items.Count - 1 do
begin
if Assigned(TreeView1.Items[i].Data) then
begin
Dispose(PUnitNodeInfo(TreeView1.Items[i].Data));
TreeView1.Items[i].Data := nil;
end;
end;
end;
// 新增
with ListView1.Items.Add do
begin
Caption := Rec^.Name;
SubItems.Add(Rec^.Code);
Data := Rec;
end;
// 讀取
Rec := PMyRecord(ListView1.Selected.Data);
// 釋放
for i := 0 to ListView1.Items.Count - 1 do
Dispose(PMyRecord(ListView1.Items[i].Data));
New/Dispose,配合 OwnerData 虛擬模式可支撐百萬級資料。