My application will be looping thru the Virtual Nodes and check their data. I am using another form to do this than the form containing the VirtualStringTree. (I got my reasons ;) )
My question is: How can I pass those nodes + their data to a function in my other form, which will then be able to loop thru the nodes (I know how to loop, I just need the nodes to be available in my other form).
Also, please note that the form that contains the VirtualStringTree is destroyed once the Processing form is being shown!
How could I do that? I am thinking about creating a dynamic VirtualStringTree, and somehow pass the nodes from 1 tree to the other, but I would ask here first for any better solutions. :)
Thanks, Jeff.
I've mentioned before that you're doing things wrong, and now you'll see why.
You're using the tree control to store your data. It's meant for displaying the data. You should have a separate data structure whose only job is to store your data. It will probably be a tree, but not a tree control. It's this tree data structure that you'd give to the processing form since it has no need for displaying nodes.
When you want to display your data, you find out how many nodes there are in the first level of your tree, and then you set your tree control's RootNodeCount
property to that number. The control will allocate that many nodes — don't call AddNewNode
for bulk operations like populating the control. When the tree is going to display a node on the screen that it hasn't displayed before, it will fire the OnInitNode
event handler. That's where you initialize the node and associate it with a value in your data structure. The tree control will tell you which node it's initializing — both via a PVirtualNode
pointer and via an index that tells which node it is, relative to its parent. When you're initializing the node, you tell the tree whether the node has any children. You don't need to tell it how many children yet; if the control wants to know, it will ask you with another event.
Now that you've separated your data from the mere presentation of your data, you no longer have to worry about the lifetime of the presenter differing from the lifetime of your data. The processing form can process the data without regard for whether the tree-view control still exists because the tree-view control never owned the data in the first place.
See also:
You've said you only have one level of nodes. That's OK. A tree with only one level is more commonly known as a list. There are several things you can use to keep track of a list. The simplest is an array. You can also use a TList
, or you can build your own linked list. This example will use an array because I want to focus on the tree control.
Let's suppose the data for each node is represented by a record, TData
, so you have an array of those:
var
Data: array of TData;
After you've loaded the array with information, from whatever source you have, you're ready to populate the tree control. That's as easy as two lines of code (one, if the control started out empty):
Tree.ResetNode(nil); // remove all existing nodes from tree
Tree.RootNodeCount := Length(Data); // allocate new nodes for all data
As the tree determines that it needs more information about any of those nodes, it will start by triggering the OnInitNode
event. There's no much you need to do for that event since the node's Index
field will be sufficient for us to find the TData
record that corresponds to any given tree node.
procedure TJeffForm.TreeInitNode(Sender: TBaseVirtualTree;
ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates);
begin
Assert(Node.Index < Length(Data), 'More nodes than data elements!?');
InitialStates := []; // If the node had children, or if it should be
// initially disabled, you'd set that here.
end;
When the tree wants to paint itself, it will ask you what text to display for each visible node by triggering the OnGetText
event. The Index
field of the node tells you which item it is, relative to its parent. (Since you just have a list, that index corresponds to the index in your list.)
procedure TJeffForm.TreeGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
Column: TColumnIndex; TextType: TVSTTextType; var CellText: UnicodeString);
begin
if TextType = ttStatic then
exit;
case Column of
NoColumn,
0: CellText := Data[Node.Index].Name;
1: CellText := 'Second column';
else
Assert(False, 'Requested text for unexpected column');
end;
end;
Above I've assumed that TData
has a string field named Name
and that that's what we should display in the main column. If the tree asks for text for anything past the second column, we'll get an assertion failure, signalling that we're not ready to release the product yet.
Notice how we use the node index to look into the entirely separate array data structure. We could destroy the tree control entirely, and the data would still exist. When your processing form needs to process data, give it the Data
array, not the tree control.
来源:https://stackoverflow.com/questions/4902471/virtualtreeview-nodes-pass-them-to-another-form