Drawing line to link treeview node of one treeview to treeview node of another treeview

一笑奈何 提交于 2020-01-03 06:41:10

问题


How is it possible to draw a line to link treeview node to another treeview node

link should be shown in from


回答1:


In WinForms TreeViews are special.

  • For one they don't have a Paint event, so it is not possible to draw on them. (You can subclass them though, see the update below..!)

  • Secondly you can't nest a transparent control in them. You can nest it but it won't be transparent..)

So drawing onto the TreeView seems to be imposible. But maybe it is not what you want anyway..?

Let's instead draw a line between two TreeViews, connection two TreeNodes n1 and n2.

Let's place the TVs onto a Panel panel1.

For testing I create two class level Points p1 and p2:

Point p1 = Point.Empty;
Point p2 = Point.Empty;

In the Panel's Paint event we draw the line:

private void panel1_Paint(object sender, PaintEventArgs e)
{
    e.Graphics.DrawLine(Pens.Firebrick, p1, p2);
}

For testing I set the Points in the NodeMouseClick event:

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

Note that the above code connects the upper left points of the nodes.

To connect the outsides of the respective lines you could calculate the points like this:

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

Update: Big thanks to Larstech for his info about overriding the WndProc method and catching WM_PAINT. I tend to block out WndProc ;-)

Using this technique it is indeed possible to draw onto a TreeView:

This screenshot uses a TreeView subclass and paints three lines: One on each TV and one on the Panel below.

Here is the TreeView class:

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

It exposes a bool to set if the TV is left or right of the other one and its BorderWidth, and a method markNode that determines which node should be connected with the lines and what slope the line has.

The NodeMouseClick has been expanded a little:

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

It now calculates the slope and calls both markNode and Invalidate on both treeviews..

No real changes in the 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);
}


来源:https://stackoverflow.com/questions/31862076/drawing-line-to-link-treeview-node-of-one-treeview-to-treeview-node-of-another-t

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!