【问题标题】:Drawing line to link treeview node of one treeview to treeview node of another treeview绘制线以将一个树视图的树视图节点链接到另一个树视图的树视图节点
【发布时间】:2015-08-06 17:25:35
【问题描述】:

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

链接应该显示在 from

【问题讨论】:

  • 这是不可能的。您可以尝试绘制两条线或用透明窗口覆盖两台电视,这会破坏交互性。您需要交互性吗?
  • 好的,告诉我怎么做。这样我就能在附近实现一些目标
  • 你愿意为此付出多少?请用美元。
  • 您的问题解决了吗?

标签: c# winforms treeview drawing paint


【解决方案1】:

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,以及一个方法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);
}

【讨论】:

  • 从技术上讲,您可以在 TreeView 控件中进行绘制。只需覆盖 WndProc 方法并查找 WM_PAINT 消息,然后使用 Graphics.FromHwnd(this.Handle)。我不会说它很漂亮。只是说。
  • @Lars:非常感谢您的提示。是的,这似乎有效。不确定我是否会使用它,但很高兴知道..
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-08-12
  • 2010-12-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多