绘制线将一个树视图的树视图节点链接到另一个树视图的树视图节点

如何绘制一条线以将树视图节点链接到另一个树视图节点

链接应显示在

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

为了测试,我在NodeMouseClick事件中设置了Points

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

它现在计算斜率并在两个树视图上调用markNodeInvalidate

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