在WinForms TreeViews 中很特别。
所以在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,以及一个方法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);
}