【问题标题】:How to make owner-drawn TreeNode class arrange items like in indented tree?如何使所有者绘制的 TreeNode 类像缩进树一样排列项目?
【发布时间】:2011-10-22 15:36:22
【问题描述】:

所以有一个很棒的开源tutorial on creating TreeNode class。太好了。但是我想知道如何改变它的 Arrange 函数来让它绘制indented tree?

函数如下:

// 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;
}

现在的样子:

缩进树的样子(图片基于DmitryG s grate answer):

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

【问题讨论】:

  • 为什么不使用内置的TreeView 来可视化您的树?
  • 它的主要观点 owner-drawn=)
  • @Kabumbus its main point of owner-drawn 这是作业吗?或者,您在寻找分包商吗?

标签: c# .net winforms treeview tree


【解决方案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);
    }
}

【讨论】:

  • 这个答案是正确的,经过测试,将在 5 小时内收到赏金(由于 SO 奖励时间限制)。
  • 顺便说一句:这是来自原始TreeNode作者blog.csharphelper.com/2011/10/25/…的回答
【解决方案2】:

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

如:

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 对象,它几乎是一个插件替代品。我将由您来决定如何绘制每个项目的线条、圆圈和文本,虽然:-)

【讨论】:

    【解决方案3】:

    实际的缩进边距和其他东西需要一些试验和错误,但这应该作为基本的伪算法工作

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

    【讨论】:

      【解决方案4】:

      TreeNode 有一个 .Level 属性,您可以使用它来确定节点缩进的距离。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多