画线将一个树形视图的树形视图节点链接到另一个树形视图的树形视图节点 [英] Drawing line to link treeview node of one treeview to treeview node of another treeview

查看:134
本文介绍了画线将一个树形视图的树形视图节点链接到另一个树形视图的树形视图节点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

链接应显示为

解决方案

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,该方法确定应该将哪个节点与这些线连接以及该线的倾斜度. /p>

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

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

link should be shown in from

解决方案

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

这篇关于画线将一个树形视图的树形视图节点链接到另一个树形视图的树形视图节点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆