6

我有一个从第三方项目文件填充的对象列表。该文件的设计方式是每个项目都位于层次结构的“级别”上。所以第一个项目在 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

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

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

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;

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

4

2 回答 2

9

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

现在走线性列表。每当您将第 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,则此代码将失败。

于 2013-11-04T16:39:18.313 回答
9

尝试这样的事情:

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;
于 2013-11-04T23:01:59.590 回答