如何使所有者绘制的TreeNode类排列缩进树中的项目?

时间:2011-10-22 15:36:23

标签: c# .net winforms treeview tree

所以有一个很棒的开源tutorial on creating TreeNode class。太棒了。但我想知道如何更改其编配功能以使其绘制indented树?

这是功能:

// Arrange the node and its children in the allowed area.
// Set xmin to indicate the right edge of our subtree.
// Set ymin to indicate the bottom edge of our subtree.
public void Arrange(Graphics gr, ref float xmin, ref float ymin)
{
    // See how big this node is.
    SizeF my_size = Data.GetSize(gr, MyFont);

    // Recursively arrange our children,
    // allowing room for this node.
    float x = xmin;
    float biggest_ymin = ymin + my_size.Height;
    float subtree_ymin = ymin + my_size.Height + Voffset;
    foreach (TreeNode<T> child in Children)
    {
        // Arrange this child's subtree.
        float child_ymin = subtree_ymin;
        child.Arrange(gr, ref x, ref child_ymin);

        // See if this increases the biggest ymin value.
        if (biggest_ymin < child_ymin) biggest_ymin = child_ymin;

        // Allow room before the next sibling.
        x += Hoffset;
    }

    // Remove the spacing after the last child.
    if (Children.Count > 0) x -= Hoffset;

    // See if this node is wider than the subtree under it.
    float subtree_width = x - xmin;
    if (my_size.Width > subtree_width)
    {
        // Center the subtree under this node.
        // Make the children rearrange themselves
        // moved to center their subtrees.
        x = xmin + (my_size.Width - subtree_width) / 2;
        foreach (TreeNode<T> child in Children)
        {
            // Arrange this child's subtree.
            child.Arrange(gr, ref x, ref subtree_ymin);

            // Allow room before the next sibling.
            x += Hoffset;
        }

        // The subtree's width is this node's width.
        subtree_width = my_size.Width;
    }

    // Set this node's center position.
    Center = new PointF(
        xmin + subtree_width / 2,
        ymin + my_size.Height / 2);

    // Increase xmin to allow room for
    // the subtree before returning.
    xmin += subtree_width;

    // Set the return value for ymin.
    ymin = biggest_ymin;
}

现在的样子:

enter image description here

缩进树的外观(基于DmitryG s grate answer的图像):

enter image description here

那么..如何让它以缩进的形式绘制图形?

4 个答案:

答案 0 :(得分:1)

您可以递归渲染树,并跟踪您所处的深度以确定缩进级别。

如:

rootNode.RenderTree(0, 0);    // Recursively draw root node at (0,0)
...


void RenderTree(int depth, ref int y)
{
    // Draw this Node at position (depth * indentAmount, y)
    ... whatever you like here to get the style of items that you want...

    depth++;               // Increase indent level (X pos) for all children
    y += thisNode.Height;  // After drawing each item, move down the page

    // Now recurse to draw all children
    foreach (Node childNode in Children)
        childNode.RenderTree(depth, ref y);
}

绘制连接线还有一些工作要做(你需要使用深度级别来告诉你要绘制多少行),但基本上就是这样。

请注意,我们将y作为ref传递,以便每个项目按顺序向下移动绘图位置,但我们按值传递深度,因为它对于树的同一级别的所有子项都是常量。

(请注意,这个伪代码与您的Arrange方法非常相似 - 只需更改名称并传入Graphics对象,它几乎就是一个插件替换。我会留给您研究如何绘制但每个项目的线条,圆圈和文字: - )

答案 1 :(得分:1)

我已经为缩进树排列修改了TreeNode.Arrange()方法 现在它看起来像这样:

public void Arrange(Graphics gr, ref float xmin, ref float ymin) {
    // See how big this node is.
    SizeF my_size = Data.GetSize(gr, MyFont);
    // Recursively arrange our children,
    // allowing room for this node.
    float y = ymin + my_size.Height;
    float biggest_xmin = xmin + my_size.Width;
    float subtree_xmin = xmin + my_size.Width + Hoffset;
    foreach(TreeNode<T> child in Children) {
        // Arrange this child's subtree.
        float child_xmin = subtree_xmin;
        child.Arrange(gr, ref child_xmin, ref y);
        // See if this increases the biggest ymin value.
        if(biggest_xmin < child_xmin) biggest_xmin = child_xmin;
        // Allow room before the next sibling.
        y += Voffset;
    }
    // Remove the spacing after the last child.
    if(Children.Count > 0) y -= Voffset;
    // See if this node is wider than the subtree under it.
    float subtree_height = y - ymin;
    if(my_size.Height > subtree_height) {
        y = ymin + (my_size.Height - subtree_height) / 2;
        foreach(TreeNode<T> child in Children) {
            // Arrange this child's subtree.
            child.Arrange(gr, ref subtree_xmin, ref y);
            y += Voffset;
        }
        subtree_height = my_size.Height;
    }
    // Set this node's center position.
    Center = new PointF(xmin + my_size.Width / 2, ymin + my_size.Height / 2);
    ymin += subtree_height;
    xmin = biggest_xmin;
}

注意,DrawSubtreLinks()方法也已被修改:

private void DrawSubtreeLinks(Graphics gr) {
    foreach(TreeNode<T> child in Children) {
        PointF p = new PointF(Center.X, child.Center.Y);
        gr.DrawLine(MyPen, Center, p);
        gr.DrawLine(MyPen, p, child.Center);
        child.DrawSubtreeLinks(gr);
    }
}

答案 2 :(得分:0)

实际的缩进边距和内容将需要一些试验和错误,但这应该作为一个基本的伪算法

创建一个存储treeNode,Depth和PrevSiblingIndex的类,然后使用它来为所有树节点填充单个数组。所以当你完成时,数组中节点的索引是它的行号(y偏移量),深度是它的缩进(x偏移量),如果PrevSiblingIndex为null,则只需要连接一行到父母。如果它不为null,则需要连接当前行中的一行,直到它的prevSibling。

答案 3 :(得分:0)

TreeNodes有一个.Level属性,可用于确定缩进节点的距离。

http://msdn.microsoft.com/en-us/library/system.windows.forms.treenode.level.aspx