I have a list of objects populated from a third-party project file. The way this file was designed is so each item is on a "level" of hierarchy. So the very first item is on level 0, all of its child items are on level 1, and so on.
As an example:
1. Node 1 (Level 0)
2. Node 1.1 (Level 1)
3. Node 1.2 (Level 1)
4. Node 1.3 (Level 1)
5. Node 1.3.1 (Level 2)
6. Node 1.4 (Level 1)
7. Node 2 (Level 0)
8. Node 2.1 (Level 1)
9. Node 2.1.1 (Level 2)
10. Node 3 (Level 0)
This would produce a hierarchy like so:
- Node 1
--- Node 1.1
--- Node 1.2
--- Node 1.3
----- Node 1.3.1
--- Node 1.4
- Node 2
--- Node 2.1
----- Node 2.1.1
- Node 3
My issue is figuring out how to populate this structure into a VCL TTreeView
based on these "Level" properties of each listed object. If I had designed this third-party file structure, I would have used a parent property instead of a level property.
Objects in this list can be iterated like this:
var
I: TMyItem;
N: TTreeNode;
begin
for X := 0 to MyList.Count - 1 do begin
I := MyList[X];
//TMyItem has property "Level" which specifies hierarchy
// as well as "Title" property for the node's caption
//How to create node based on Level?
N.Data := I;
end;
end;
Based on this structure, how do I populate this in a tree view?
Try something like this:
var
Item: TMyItem;
Node: TTreeNode;
NodeLevel: Integer;
X: Integer;
begin
Node := nil;
NodeLevel := 0;
for X := 0 to MyList.Count-1 do
begin
Item := MyList[X];
if (Node = nil) or (Item.Level <= 0) then
begin
Node := TreeView1.Items.AddObject(nil, Item.Text, Item);
NodeLevel := 0;
end
else if Item.Level = NodeLevel then
begin
Node := TreeView1.Items.AddObject(Node, Item.Text, Item);
end else
begin
while Item.Level <= NodeLevel do
begin
Node := Node.Parent;
Dec(NodeLevel);
end;
Node := TreeView1.Items.AddChildObject(Node, Item.Text, Item);
Inc(NodeLevel);
end;
// set Node properties as needed...
end;
end;
Create a list that will contain the latest parent node for each level. Initially this list will be empty.
Now walk the linear list. Whenever you add an item at level N to the list, you do the following:
You'll need to handle the case where N=0 for which the above algo would require you to come up with the latest parent at level -1, whatever that means. Does your tree have an overall root node? If so, then by definition, the latest parent at level -1 is the root node. Otherwise, if there's no root node, you'll need do whatever your tree view component requires to add a node at the top level, as opposed to as a child of another node.
Assuming that there is no root node, then the code would look like this:
var
Item: TItem;
LatestParents: TList<TTreeNode>;
Parent, NewNode: TTreeNode;
begin
LatestParents := TList<TTreeNode>.Create;
try
LatestParents.Add(nil);
for Item in Items do
begin
Parent := LatestParents[Item.Level];
NewNode := TreeView.Items.AddChild(Parent, Item.Text);
LatestParents.Count := Max(LatestParents.Count, Item.Level+2);
LatestParents[Item.Level+1] := NewNode;
end;
finally
LatestParents.Free;
end;
end;
You may want to put some error checking into the code if there's a possibility of your code encountering a malformed description of the tree. For instance if the first node that you encounter does not have level 0, then this code will fail.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With