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