如何基于具有“级别”的平面列表填充树视图?

时间:2013-11-04 16:32:58

标签: delphi treeview hierarchy

我有一个从第三方项目文件填充的对象列表。设计此文件的方式是每个项目都处于层次结构的“级别”。所以第一个项目在0级,所有子项目都在1级,依此类推。

举个例子:

  1. Node 1     (Level 0)
  2. Node 1.1   (Level 1)
  3. Node 1.2   (Level 1)
  4. Node 1.3   (Level 1)
  5. Node 1.3.1 (Level 2)
  6. Node 1.4   (Level 1)
  7. Node 2     (Level 0)
  8. Node 2.1   (Level 1)
  9. Node 2.1.1 (Level 2)
 10. Node 3     (Level 0)

这会产生如下的层次结构:

- Node 1
--- Node 1.1
--- Node 1.2
--- Node 1.3
----- Node 1.3.1
--- Node 1.4
- Node 2
--- Node 2.1
----- Node 2.1.1
- Node 3

我的问题是弄清楚如何根据每个列出的对象的这些“级别”属性将此结构填充到VCL TTreeView中。如果我设计了这个第三方文件结构,我会使用父属性而不是级别属性。

此列表中的对象可以像这样迭代:

var
  I: TMyItem;
  N: TTreeNode;
begin
  for X := 0 to MyList.Count - 1 do begin
    I := MyList[X];
    //TMyItem has property "Level" which specifies hierarchy
    //  as well as "Title" property for the node's caption
    //How to create node based on Level?

    N.Data := I;
  end;  
end;

基于这种结构,我如何在树状视图中填充它?

2 个答案:

答案 0 :(得分:8)

创建一个列表,其中包含每个级别的最新父节点。最初此列表将为空。

现在走线性列表。每当您将N级项目添加到列表中时,您都会执行以下操作:

  • 将其添加为级别为N-1且
  • 的最新父级的子级
  • 将级别N的最新父级设置为刚刚添加的项目。

你需要处理N = 0的情况,上面的算法要求你在-1级提出最新的父级,无论这意味着什么。您的树是否有整体根节点?如果是这样,那么根据定义,级别-1的最新父级是根节点。否则,如果没有根节点,您将需要执行树视图组件在顶层添加节点所需的任何内容,而不是另一个节点的子节点。

假设没有根节点,那么代码将如下所示:

var
  Item: TItem;
  LatestParents: TList<TTreeNode>;
  Parent, NewNode: TTreeNode;
begin
  LatestParents := TList<TTreeNode>.Create;
  try
    LatestParents.Add(nil);
    for Item in Items do
    begin
      Parent := LatestParents[Item.Level];
      NewNode := TreeView.Items.AddChild(Parent, Item.Text);
      LatestParents.Count := Max(LatestParents.Count, Item.Level+2);
      LatestParents[Item.Level+1] := NewNode;
    end;
  finally
    LatestParents.Free;
  end;
end;

如果您的代码可能遇到格式错误的树形描述,您可能需要对代码进行一些错误检查。例如,如果您遇到的第一个节点没有级别0,则此代码将失败。

答案 1 :(得分:7)

尝试这样的事情:

var
  Item: TMyItem;
  Node: TTreeNode;
  NodeLevel: Integer;
  X: Integer;
begin
  Node := nil;
  NodeLevel := 0;
  for X := 0 to MyList.Count-1 do
  begin
    Item := MyList[X];
    if (Node = nil) or (Item.Level <= 0) then
    begin
      Node := TreeView1.Items.AddObject(nil, Item.Text, Item);
      NodeLevel := 0;
    end
    else if Item.Level = NodeLevel then
    begin
      Node := TreeView1.Items.AddObject(Node, Item.Text, Item);
    end else
    begin
      while Item.Level <= NodeLevel do
      begin
        Node := Node.Parent;
        Dec(NodeLevel);
      end;
      Node := TreeView1.Items.AddChildObject(Node, Item.Text, Item);
      Inc(NodeLevel);
    end;
    // set Node properties as needed...
  end;
end;