【问题标题】:VirtualTreeview Nodes, pass them to another form?VirtualTreeview 节点,将它们传递给另一种形式?
【发布时间】:2011-02-04 20:13:09
【问题描述】:

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

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

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

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

谢谢,杰夫。

【问题讨论】:

    标签: delphi virtualtreeview


    【解决方案1】:

    I've mentioned before 你做错事了,现在你就会明白为什么了。

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

    当您想要显示您的数据时,您需要了解树的第一级中有多少个节点,然后将树控件的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数组,而不是树形控件。

    【讨论】:

    • 我的树只有 1 级节点。我不太确定你刚才说的该怎么做。你介意给我一个伪例子吗?我对 Delphi 并没有那么深入,我现在通常只使用可视化控件。
    • @Jeff 你的意思是没有层次结构吗?一切都在同一水平?如果是这样,那么只需将您的节点存储在一个列表中!
    • @Jeff SetLength(Data, Count); for i := 0 to Count-1 do Data[i] := ReadItem;
    • @Jeff 或Generics.Collections.TList&lt;TData&gt; 会转到for i := 0 to Count-1 do Data.Add(ReadItem);
    • @jeff ReadItem 是您的代码!它是填充您的数据的任何内容。您必须尝试查看模式和技术,而不是查看特定问题的详细细节。
    猜你喜欢
    • 2012-08-17
    • 1970-01-01
    • 2017-06-17
    • 1970-01-01
    • 2015-06-23
    • 1970-01-01
    相关资源
    最近更新 更多