如何绘制一条线以将树视图节点链接到另一个树视图节点
链接应显示在
中
答案 0 :(得分:4)
在WinForms
TreeViews
中很特别。
对于他们没有Paint
事件的人,所以无法在他们身上画画。
(您可以将它们子类化,请参阅下面的更新..!)
其次,您无法在其中嵌套透明控件。你可以嵌套它,但它不会透明。)
所以吸引TreeView
似乎是不可能的。但也许它不是你想要的......?
我们改为在两个TreeViews
之间划线,连接两个TreeNodes
n1和n2。
我们将电视放在Panel panel1
上。
为了测试我创建了两个类级别Points p1 and p2
:
Point p1 = Point.Empty;
Point p2 = Point.Empty;
在Panel's Paint
事件中我们画线:
private void panel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawLine(Pens.Firebrick, p1, p2);
}
为了进行测试,我在Points
事件中设置了NodeMouseClick
:
private void treeView1_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
TreeNode n1 = e.Node;
// for testing I search for a corresponding node:
TreeNode n2 = treeView2.Nodes.Find(n1.Name, true).First();
// for testing I select the node:
treeView2.SelectedNode = n2;
// top left points in the node:
p1 = n1.Bounds.Location;
p2 = n2.Bounds.Location;
// add the offset of the treviews:
p1.Offset(treeView1.Left, treeView1.Top);
p2.Offset(treeView2.Left, treeView2.Top);
// trigger the paint event;
panel1.Invalidate();
}
请注意,上面的代码连接节点的左上角。
要连接相应行的外部,您可以计算如下所示的点:
p1 = new Point(treeView1.Right, n1.Bounds.Top + n1.Bounds.Height / 2 + treeView1.Top);
p2 = new Point(treeView2.Left, n2.Bounds.Top + n2.Bounds.Height / 2 + treeView2.Top);
更新:非常感谢Larstech提供有关覆盖WndProc方法和捕获WM_PAINT的信息。我倾向于阻止WndProc; - )
使用这种技术确实可以绘制到TreeView:
此屏幕截图使用TreeView
子类并绘制三行:每个电视一个,下面面板一个。
以下是TreeView
类:
class PTreeView : TreeView
{
public bool IsLeft { get; set; }
public int BorderWidth { get; private set; }
private float slope { get; set; }
private Point Pt { get; set; }
public PTreeView() { }
public void markNode(TreeNode node, float slope_)
{
if (this.IsLeft ) Pt =
new Point(node.Bounds.Right, node.Bounds.Top + node.Bounds.Height / 2);
else Pt = new Point(node.Bounds.Left, node.Bounds.Top + node.Bounds.Height / 2);
slope = slope_;
BorderWidth = (this.Width - this.ClientRectangle.Width) / 2;
}
internal const int WM_PAINT = 0xF;
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == WM_PAINT)
{
Graphics G = this.CreateGraphics();
G.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
int px = IsLeft ? this.ClientRectangle.Width : 0;
int py = (int)(Pt.Y + slope * (Pt.X - px));
Point p0 = new Point(px, py);
G.DrawLine(Pens.Coral, Pt, p0);
}
}
}
如果电视是另一个电视的左侧或右侧及其BorderWidth
,则公开bool以设置bool,以及确定哪个节点应与线路连接的方法markNode
以及有线。
NodeMouseClick
已经扩展了一点:
private void treeView1_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
TreeNode n1 = e.Node;
TreeNode n2 = treeView2.Nodes.Find(n1.Name, true).First();
treeView2.SelectedNode = n2;
p1 = new Point(
treeView1.Left + n2.Bounds.Left + n1.Bounds.Width + treeView1.BorderWidth,
treeView1.Top + n1.Bounds.Top + n1.Bounds.Height / 2 + treeView1.BorderWidth);
p2 = new Point(
treeView2.Left + n2.Bounds.Left + treeView2.BorderWidth,
treeView2.Top + n2.Bounds.Top + n2.Bounds.Height / 2 + treeView2.BorderWidth);
float slope = -1f * (p2.Y - p1.Y) / (p2.X - p1.X);
treeView1.markNode(n1, slope);
treeView2.markNode(n2, slope);
panel1.Invalidate();
treeView1.Invalidate();
treeView2.Invalidate();
}
它现在计算斜率并在两个树视图上调用markNode
和Invalidate
..
Panel Paint中没有真正的变化:
private void panel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
e.Graphics.DrawLine(Pens.Coral, p1, p2);
}