1

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

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

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

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

谢谢,杰夫。

4

1 回答 1

13

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

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

当你想显示你的数据时,你会发现在你的树的第一层有多少个节点,然后你将你的树控件的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数组,而不是树控件。

于 2011-02-04T20:47:21.033 回答