VirtualTreeview 节点,将它们传递给另一种形式?

发布于 2024-10-15 23:23:48 字数 329 浏览 1 评论 0原文

我的应用程序将循环通过虚拟节点并检查它们的数据。我使用另一种形式来执行此操作,而不是包含 VirtualStringTree 的形式。 (我有我的理由;))

我的问题是:如何将这些节点+它们的数据传递给我的其他形式的函数,然后该函数将能够循环通过节点(我知道如何循环,我只需要节点以我的其他形式可用)。

另外,请注意,一旦显示处理表单,包含 VirtualStringTree 的表单就会被销毁!

我怎么能这么做呢?我正在考虑创建一个动态 VirtualStringTree,并以某种方式将节点从一棵树传递到另一棵树,但我首先会在这里询问是否有更好的解决方案。 :)

谢谢,杰夫。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

月下伊人醉 2024-10-22 23:23:48

我之前提到过你做错了,现在你会看看为什么。

您正在使用树控件来存储数据。它用于显示数据。您应该有一个单独的数据结构,其唯一的作用是存储数据。它可能是一个,但不是树控件。您将向处理表单提供此树数据结构,因为它不需要显示节点。

当您想要显示数据时,您可以找出树的第一层中有多少个节点,然后将树控件的 RootNodeCount 属性设置为该数字。控件将分配那么多节点 - 不要调用 AddNewNode 进行批量操作(例如填充控件)。当树要在屏幕上显示以前未显示过的节点时,它将触发 OnInitNode 事件处理程序。您可以在此处初始化节点并将其与数据结构中的值关联起来。树控件将告诉您它正在初始化哪个节点 - 通过 PVirtualNode 指针和索引来告诉您相对于其父节点它是哪个节点。当您初始化节点时,您会告诉树该节点是否有任何子节点。您不需要告诉它还有多少个孩子;如果控件想知道,它会询问您另一个事件。

现在,您已经将数据与数据的单纯表示分离,您不再需要担心表示器的生命周期与数据的生命周期不同。处理窗体可以处理数据,而无需考虑树视图控件是否仍然存在,因为树视图控件从一开始就从未拥有过数据。

另请参阅:


您说过您只有一层节点。没关系。只有一层的树通常称为列表。您可以使用多种方法来跟踪列表。最简单的是数组。您还可以使用 TList,或者构建您自己的链接列表。本示例将使用数组,因为我想重点关注树控件。

假设每个节点的数据都由一条记录 TData 表示,因此您有一个由这些记录组成的数组:

var
  Data: array of TData;

在从您拥有的任何来源加载包含信息的数组后,您就准备好了填充树控件。这就像两行代码一样简单(一行,如果控件开始为空):

Tree.ResetNode(nil); // remove all existing nodes from tree
Tree.RootNodeCount := Length(Data); // allocate new nodes for all data

当树确定它需要有关任何这些节点的更多信息时,它将首先触发 OnInitNode 事件。您无需为该事件执行太多操作,因为节点的 Index 字段足以让我们找到与任何给定树节点相对应的 TData 记录。

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;

当树想要绘制自己时,它会通过触发 OnGetText 事件询问您为每个可见节点显示什么文本。节点的 Index 字段告诉您它是相对于其父项的哪个项目。 (因为您只有一个列表,所以该索引对应于列表中的索引。)

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;

上面我假设 TData 有一个名为 Name 的字符串字段,这就是我们应该显示在主栏中。如果树要求提供第二列之后的任何文本,我们将收到断言失败,表明我们尚未准备好发布产品。

请注意我们如何使用节点索引来查看完全独立的数组数据结构。我们可以完全销毁树控件,而数据仍然存在。当你的处理表单需要处理数据时,给它Data数组,而不是树形控件。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文