如何画线,并在面板中选择它 [英] How to draw line and select it in Panel

查看:123
本文介绍了如何画线,并在面板中选择它的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的程序可以使用canvas.Drawline()绘制线条。如何点击线并更改此颜色(选择线)?

 私人列表< Point& coordFirst = new List< Point>(); 
private List< Point> coordLast = new List< Point>();
public Graphics canvas;

private void Form1_Load(object sender,EventArgs e)
{
canvas = panel1.CreateGraphics();
}

坐标线存储在coordFirs& coodLast。

解决方案

这是一个合适的 Line 类:

  class Line 
{
public Color LineColor {get;组; }
public float Linewidth {get;组; }
public bool Selected {get;组; }
public Point Start {get;组; }
public Point End {get;组; }

public Line(Color c,float w,Point s,Point e)
{LineColor = c; Linewidth = w; Start = s; End = e; }

public void Draw(Graphics G)
{using(Pen pen = new Pen(LineColor,Linewidth))G.DrawLine(pen,Start,End); }

public bool HitTest(Point Pt)
{
//测试如果我们超出边界框:
if((Pt.X //现在我们计算距离:
float dy = End.Y - Start.Y;
float dx = End.X - Start.X;
float Z = dy * Pt.X - dx * Pt.Y + Start.Y * End.X - Start.X * End.Y;
float N = dy * dy + dx * dx;
float dist =(float)(Math.Abs​​(Z)/ Math.Sqrt(N));
// done:
return dist<线宽/ 2f;
}

}

定义行的列表,可能在类级别:

 列表< Line& lines = new List< Line>(); 

以下是如何用几行初始化它:

  for(int i = 0; i <20; i ++)lines.Add(new Line(Color.Black,4f,
new Point .Next(panel1.Width),R.Next(panel1.Height)),
new Point(R.Next(panel1.Width),R.Next(panel1.Height))));

这是点击十字路口的结果:





每当您添加,更改或删除一行时,您需要使 Panel 通过触发 Paint 事件反映新闻:

 code> panel1.Invalidate(); 

这里是 Paint code> Panel :

  private void panel1_Paint(object sender,PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
foreach(Line L in lines)L.Draw(e.Graphics);
}

MouseClick 事件你做测试:

  private void panel1_MouseClick(object sender,MouseEventArgs e)
{
foreach (行L中的行)
L.LineColor = L.HitTest(e.Location)?颜色:
panel1.Invalidate();
}

为避免闪烁,请不要使用基本的面板类,因为它不是 doublebuffered 。而是使用 PictureBox doublebuffered Panel 子类:

  class DrawPanel:Panel 
{public DrawPanel(){DoubleBuffered = true; }}

注意




  • 在WinForms中没有Line这样的东西,只有各种颜色的像素。所以要选择一行,你需要存储它的两个端点的坐标,然后找出是否你点击它。


  • 上述示例显示了如何在数学中完成此操作。


  • 而是可以通过将每一行绘制到位图上并测试鼠标点击的像素来测试每一行。但是绘制这些位图也必须在幕后做数学运算,并为位图分配空间,因此数学将更有效率。


  • Line 类看起来有点长,这样一个简单的东西asa行,但看看现在所有的事件代码多么短!


  • 还要注意,在WinForms中执行任何绘图的第一条规则是:从不缓存或存储 Grahics 对象。实际上,你不应该 CreateGraphics 放在第一位,因为 Graphics 对象将永远不会停留在范围内,并且它生成的图形不会持续(即生存最小化 - 最大化序列)。


  • 另请注意我如何传递输出 Paint 事件参数的 e.Graphics Line 实例,以便用当前的 Graphics 对象绘制自己!

  • $ b href =https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line#Line_defined_by_two_points =nofollow noreferrer>维基百科。



My program can draw lines using canvas.Drawline(). How to click line and change this color (select line)?

private List<Point> coordFirst = new List<Point>();
private List<Point> coordLast = new List<Point>();
public Graphics canvas;

        private void Form1_Load(object sender, EventArgs e)
        {
            canvas=panel1.CreateGraphics();
        }

Coordinate line stored in coordFirs & coodLast.

解决方案

Here is a suitable Line class:

class Line
{
    public Color LineColor { get; set; }
    public float Linewidth { get; set; }
    public bool Selected { get; set; }
    public Point Start { get; set; }
    public Point End { get; set; }

    public Line(Color c, float w, Point s, Point e)
    { LineColor = c; Linewidth = w; Start = s; End = e;    }

    public void Draw(Graphics G)
    { using (Pen pen = new Pen(LineColor, Linewidth)) G.DrawLine(pen, Start, End); }

    public bool HitTest(Point Pt)
    {
        // test if we fall outside of the bounding box:
        if ((Pt.X < Start.X && Pt.X < End.X) || (Pt.X > Start.X && Pt.X > End.X) ||
            (Pt.Y < Start.Y && Pt.Y < End.Y) || (Pt.Y > Start.Y && Pt.Y > End.Y)) 
            return false;
        // now we calculate the distance:
        float dy = End.Y - Start.Y;
        float dx = End.X - Start.X;
        float Z = dy * Pt.X - dx * Pt.Y + Start.Y * End.X - Start.X * End.Y;
        float N = dy * dy + dx * dx;
        float dist = (float)( Math.Abs(Z) / Math.Sqrt(N));
        // done:
        return dist < Linewidth / 2f;
    }

}

Define a List for the lines, probably at class level:

    List<Line> lines = new List<Line>();

Here is how you can initialize it with a few lines:

for (int i = 0; i < 20; i++) lines.Add(new Line(Color.Black, 4f, 
    new Point(R.Next(panel1.Width), R.Next(panel1.Height)), 
    new Point(R.Next(panel1.Width), R.Next(panel1.Height))));

Here is the result of clicking on a crossing:

Whenever you add, change or remove a line you need to make the Panel reflect the news by triggering the Paint event:

panel1.Invalidate();

Here is the Paint event of the Panel:

private void panel1_Paint(object sender, PaintEventArgs e)
{
    e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
    foreach (Line L in lines) L.Draw(e.Graphics);
}

In the MouseClick event you do the test:

private void panel1_MouseClick(object sender, MouseEventArgs e)
{
    foreach(Line L in lines) 
            L.LineColor = L.HitTest(e.Location) ?  Color.Red : Color.Black;
    panel1.Invalidate();
}

To avoid flicker don't use the basic Panel class as it isn't doublebuffered. Instead use either a PictureBox or a doublebuffered Panel subclass:

class DrawPanel : Panel 
{     public DrawPanel ()   { DoubleBuffered = true; }   }

Notes:

  • There is no such thing as a 'Line' in WinForms, only pixels of various colors. So to select a line you need to store it's two endpoints' coordinates and then find out if you have hit it when clicking.

  • The above example shows how to do it in math.

  • Instead one could test each line by drawing it onto a bitmap and test the pixel the mouse has clicked. But drawing those bitmaps would have to do math behind the scenes as well and also allocate space for the bitmaps, so the math will be more efficient..

  • Yes the Line class looks a little long for such a simple thing a s a line but look how short all the event codes now are! That's because the responsiblities are where they belong!

  • Also note the the first rule of doing any drawing in WinForms is: Never cache or store a Grahics object. In fact you shouldn't ever use CreateGraphics in the first place, as the Graphics object will never stay in scope and the graphics it produces will not persist (i.e. survive a Minimize-maximize sequence)..

  • Also note how I pass out the e.Graphics object of the Paint event's parameters to the Line instances so they can draw themselves with a current Graphics object!

  • To select thinner lines it may help to modify the distance check a little..

  • The Math was taken directly form Wikipedia.

这篇关于如何画线,并在面板中选择它的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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