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

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

问题描述

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

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

坐标线存储在 coordFirs &冷最后.

Coordinate line stored in coordFirs & coodLast.

推荐答案

这是一个合适的 Line 类:

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:

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

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

panel1.Invalidate();

这是PanelPaint事件:

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

MouseClick 事件中进行测试:

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

为了避免闪烁,不要使用基本的 Panel 类,因为它不是 doublebuffered.而是使用 PictureBoxLabel(使用 AutoSize=false)或 doublebuffered Panel 子类:

To avoid flicker don't use the basic Panel class as it isn't doublebuffered. Instead use either a PictureBox or a Label (with AutoSize=false) or a doublebuffered Panel subclass:

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

注意事项:

  • WinForms 中没有线条"这样的东西,只有各种颜色的像素.因此,要选择一条线,您需要存储它的两个端点的坐标,然后在单击时确定您是否点击了它.

  • 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..

是的,Line 类对于一行这样简单的东西来说看起来有点长,但看看现在所有的事件代码是多么的短!那是因为责任是它们的归属!

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!

还要注意在 WinForms 中进行任何绘图的第一条规则是:从不缓存或存储 Grahics 对象.事实上,您一开始就不应该使用 CreateGraphics,因为Graphics 对象永远不会停留在范围内,它生成的图形也会不坚持(即在最小化-最大化序列中幸存下来)..

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

还要注意我如何传递Paint事件参数的e.Graphics对象到Line 实例,以便他们可以使用当前的 Graphics 对象绘制自己!

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..

数学直接取自维基百科.

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

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