There are two things which must be available in the nodes:
- the record associated with the clicked subtree (Name - Status/ExpiryDate/JoinDate)
- the field associated with the clicked node
I store in each node of the subtree the RecNo which is fine for BufDataset but probably not for TSQLQuery/TZQuery. Your database must contain a column, ideally an integer field, by which each record can be identified uniquely.
But putting the ID value into the Data field of each node of the subtree leaves no space for how to find the field from the clicked node. I solved this by putting some field-identifying text into the node's Text property, e.g. "Expiry date: " - clicking on this node makes clear that this is for the ExpiryDate field. If you can follow this convention, my solution will work.
If you cannot then you should store the associated field in the node's Data:
procedure TForm1.PopulateTree;
var
node: TTreeNode;
id: PtrInt;
field: TField;
begin
TreeView1.Items.Clear;
ZQuery1.DisableControls;
try
ZQuery1.First;
while not ZQuery1.EoF do
begin
id := ZQuery1.FieldByName('ID').AsInteger;
node := Treeview1.Items.AddChildObject(nil, ZQuery.FieldByName('Name').AsString, pointer(id));
field := ZQuery1.FieldByName('Status');
TreeView1.Items.AddChildObject(node, < some text >, field);
field := ZQuery1.FieldByName('ExpiryDate');
Treeview1.Items.AddChildObject(node, < some text >, field);
field := ZQuery1.FieldByName('JoinDate');
Treeview1.Items.AddChildObject(node, < some text >, field);
node.Expanded := true;
ZQuery1.Next;
end;
finally
ZQuery1.EnableControls;
end;
end;
However, now the subnodes do no longer know to which record they belong. Therefore, in above snippet, I assumed that the "Name" node is always the top node and stored the record ID here. So, when you click on a subnode you must navigate to the top node and extract the record ID from there.
The cleanest solution, however, is to create a new TTreeNode class with an extra field for the RecordID info:
type
TExtendedTreeNode = class(TTreeNode)
private
FRecordID: Integer;
public
property RecordID: Integer read FRecordID write FRecordID;
end;
To make sure that the Tree creates nodes of this type you must provide a handler for the TOnCreateNodeClass event:
procedure TForm1.TreeView1CreateNodeClass(Sender: TObject; var NodeClass: TTreeNodeClass);
begin
NodeClass := TExtendedTreeNode;
end;
Now, when you populate the tree you can set the RecordID directly for every node:
procedure TForm1.PopulateTree;
var
topnode, node: TTreeNode;
id: PtrInt;
field: TField;
begin
TreeView1.Items.Clear;
ZQuery1.DisableControls;
try
ZQuery1.First;
while not ZQuery1.EoF do
begin
id := ZQuery1.FieldByName('ID').AsInteger;
field := ZQuery1.FieldByName('Name');
topnode := Treeview1.Items.AddChildObject(nil, < some text >, field);
(topNode as TExtendedTreeNode).RecordID := id;
field := ZQuery1.FieldByName('Status');
node := TreeView1.Items.AddChildObject(topnode, < some text >, field);
(node as TExtendedTreeNode).RecordID := id;
field := ZQuery1.FieldByName('ExpiryDate');
node := Treeview1.Items.AddChildObject(topnode, < some text >, field);
(node as TExtendedTreeNode).RecordID := id;
field := ZQuery1.FieldByName('JoinDate');
node := Treeview1.Items.AddChildObject(topnode, < some text >, field);
(node as TExtendedTreeNode).RecordID := id;
topnode.Expanded := true;
ZQuery1.Next;
end;
finally
ZQuery1.EnableControls;
end;
end;
In this solution all nodes have the associated field in the node's Data, and the RecordID is available in the node's new RecordID property (however, you must cast the node to TExtendedTreeNode to get access to it).
Please note that the code fragments shown were not tested and may contain typos and logical errors. But I hope you understood the principle.