VirtualTreeview Nodes, pass them to another form?

若如初见. 提交于 2019-12-09 08:21:27
Rob Kennedy

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!