C# 如何使所有者绘制的TreeNode类像在缩进树中那样排列项目?

C# 如何使所有者绘制的TreeNode类像在缩进树中那样排列项目?,c#,.net,winforms,treeview,tree,C#,.net,Winforms,Treeview,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

所以有一个很棒的开源软件。太棒了。但我想知道如何改变它的排列功能,使它画树

下面是函数:

// 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;
}
//在允许的区域中排列节点及其子节点。
//设置xmin以指示子树的右边缘。
//设置ymin以指示子树的底边。
公共空间排列(图形gr、参考浮动xmin、参考浮动ymin)
{
//看看这个节点有多大。
SizeF my_size=Data.GetSize(gr,MyFont);
//递归地安排我们的孩子,
//允许此节点有空间。
浮动x=xmin;
浮动最大值=ymin+my_size.Height;
float subtree_ymin=ymin+my_size.Height+Voffset;
foreach(儿童中的TreeNode儿童)
{
//排列此孩子的子树。
float child_ymin=子树_ymin;
儿童安排(gr、ref x、ref child_ymin);
//看看这是否会增加最大的ymin值。
如果(最大值<儿童值)最大值=儿童值;
//在下一个兄弟姐妹之前留出空间。
x+=Hoffset;
}
//删除最后一个子项后的间距。
如果(Children.Count>0)x-=Hoffset;
//查看此节点是否比其下的子树宽。
浮动子树_宽度=x-xmin;
if(my_size.Width>子树宽度)
{
//将子树居中放置在此节点下。
//让孩子们重新安排自己
//移动到子树的中心。
x=xmin+(my_size.Width-子树宽度)/2;
foreach(儿童中的TreeNode儿童)
{
//排列此孩子的子树。
排列(gr、ref x、ref子树_ymin);
//在下一个兄弟姐妹之前留出空间。
x+=Hoffset;
}
//子树的宽度是此节点的宽度。
子树宽度=我的大小.width;
}
//设置此节点的中心位置。
中心=新点F(
xmin+子树_宽度/2,
ymin+my_size.Height/2);
//增加xmin以留出空间
//返回之前的子树。
xmin+=子树的宽度;
//设置ymin的返回值。
ymin=最大值;
}
现在的样子:

缩进树的外观(基于图像):


所以。。如何使它以缩进的形式绘制图形?

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


创建一个存储treeNode、Depth和PrevSiblingIndex的类,然后使用该类为所有树节点填充单个数组。因此,完成后,数组中节点的索引是它的行号(y偏移),深度是它的缩进(x偏移),如果PrevSiblingIndex为null,则只需将一行连接到父节点。如果不为null,则需要连接当前行到其上一个同级的行。

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


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

例如:

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方法非常相似-只需更改名称并传入图形对象,它几乎就是一个插件替代品。我将让您自行决定如何为每个项目绘制线条、圆圈和文本:-)

我已经修改了用于缩进树排列的TreeNode.Arrange()方法。
现在看起来是这样的:

public void Arrange(图形gr、ref float xmin、ref float ymin){
//看看这个节点有多大。
SizeF my_size=Data.GetSize(gr,MyFont);
//递归地安排我们的孩子,
//允许此节点有空间。
浮动y=ymin+my_size.Height;
浮动最大值xmin=xmin+my_size.Width;
浮动子树_xmin=xmin+my_size.Width+Hoffset;
foreach(儿童中的TreeNode儿童){
//排列此孩子的子树。
浮动子树_xmin=子树_xmin;
子排列(gr,ref child_xmin,ref y);
//看看这是否会增加最大的ymin值。
如果(最大值xmin<子值xmin)最大值xmin=子值xmin;
//在下一个兄弟姐妹之前留出空间。
y+=Voffset;
}
//删除最后一个子项后的间距。
如果(Children.Count>0)y-=Voffset;
//查看此节点是否比其下的子树宽。
浮动子树高度=y-ymin;
if(my_size.Height>子树高度){
y=ymin+(my_size.Height-子树高度)/2;
foreach(儿童中的TreeNode儿童){
//排列此孩子的子树。
排列(gr,ref子树_xmin,ref y);
y+=Voffset;
}
子树高度=我的尺寸高度;
}
//设置此节点的中心位置。
中心=新点F(xmin+my_size.Width/2,ymin+my_size.Height/2);
ymin+=子树高度;
xmin=最大值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);
    }
}
private void DrawSubtreeLinks(图形组){
foreach(儿童中的TreeNode儿童){
点F p=新点F(中心点X,子中心点Y);
gr.抽绳(MyPen,中心,p);
gr.抽绳(MyPen,p,儿童中心);
子卷纸油墨(gr);
}
}

为什么不使用内置工具来可视化您的树?其所有者绘制的要点=)@Kabumbus
其所有者绘制的要点
这是家庭作业吗?或者,您是否正在寻找分包商?此答案正确且经过测试,将在5小时内收到赏金(到期)
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);
    }
}