【问题标题】:How to draw a small dot on every click of the mouse in a PictureBox如何在 PictureBox 中每次单击鼠标时绘制一个小点
【发布时间】:2018-10-01 21:59:44
【问题描述】:

我有一个WinForms 程序,用户在其中单击PictureBox 控件。
每次用户点击时,我都想要一个小红点(跨越几个像素)。
我也不希望之前的任何点消失。

我知道我需要一个椭圆和矩形的通用列表,但不知道如何执行。我该怎么做呢?

在我的程序中,pictureBox1_Click 方法处理鼠标点击事件并返回点击的位置。
pictureBox1_Paint 方法处理要在这些点上绘制的图形。

【问题讨论】:

  • PictureBox 有一个 Paint 事件。它已经知道如何自己绘制它的 Image 属性,你可以在它上面添加任何你需要的东西。您唯一需要做的就是告诉它重新绘制并再次触发它的 Paint 事件,我们使用它的 Invalidate() 方法。
  • 感谢@HansPassant,到目前为止,我正在 Click 方法中创建矩形对象,我是否只是将对象数组传递给 Paint 方法?
  • 您需要存储要绘制的数据列表,例如类级别,可能是 List 或 List 等。

标签: c# winforms graphics gdi+


【解决方案1】:

您必须创建一个可以引用 Points 集合的容器,并在每次单击可绘制控件时向该集合添加一个点。

也许,您还想根据某些条件或要求创建不同类型的绘图
因此,您还需要存储这些额外的属性,而不仅仅是点坐标。
如果是这样,您需要一个可以在需要时公开这些属性的专用对象。

所以,这里有一个自定义的Class 对象,它具有一些简单的属性,可以让您定义点的颜色和大小。对于它的每个积分集合。
它还实现了 IDisposable 接口,因为我们需要为我们绘制的每个 Point 创建一个 Pen 对象。并且需要处理 Pen 对象(实现 IDisposable)。

要执行绘图,您只需调用Control.Invalidate()(示例中为pictureBox1.Invalidate())。这会导致控件无效部分的重新绘制,引发 OnPaint() 事件。
每个点(需要重新绘制)都是使用 e.Graphics.DrawEllipse() 绘制的。

你可以这样测试:

使用预定义属性,仅使用鼠标指针坐标:

myPoints.Add(new MyPoints.DrawingPoint(e.Location));

当需要不同的东西时具有特定的属性:

尺寸为 8x8 像素
newPoint.Dot = new Rectangle(e.Location, new Size(8, 8)));

使用 2 像素大小的橙色 Pen
newPoint.DrawingPen = new Pen(Color.Orange, 2);

将此新点添加到集合中
myPoints.DrawingPoints.Add(newPoint);

Clear() 方法用于Dispose() 当前的点列表并创建一个新的空列表:
MyPoints.Clear();

示例实现

MyPoints myPoints = new MyPoints();

private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
    //Use default property values
    //myPoints.Add(new MyPoints.DrawingPoint(e.Location));

    MyPoints.DrawingPoint newPoint = new MyPoints.DrawingPoint();
    newPoint.Dot = new Rectangle(e.Location, new Size(4, 4));
    newPoint.DrawingPen = new Pen(Color.Red, 2);
    myPoints.DrawingPoints.Add(newPoint);
    (sender as Control).Invalidate();
}

private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
    foreach (MyPoints.DrawingPoint mypoint in myPoints.DrawingPoints) {
        e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
        e.Graphics.DrawEllipse(mypoint.DrawingPen, mypoint.Dot);
    }
}

private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
    myPoints.Dispose();
}

Point对象集合类容器

internal class MyPoints : IDisposable
{
    bool IsDisposed = false;
    public MyPoints() => DrawingPoints = new List<DrawingPoint>();

    public List<DrawingPoint> DrawingPoints { get; set; }
    public void Add(DrawingPoint NewPoint)
    {
        if (NewPoint.Dot.Size.Width > 1 && NewPoint.Dot.Size.Height > 1) {
            DrawingPoints.Add(NewPoint);
        }
    }

    public void Clear()
    {
        this.Dispose();
        this.DrawingPoints.Clear();
        this.DrawingPoints = new List<DrawingPoint>();
    }

    public void Remove(Point point)
    {
        Remove(this.DrawingPoints.Select((p, i) => { if (p.Dot.Contains(point)) return i; return -1; }).First());
    }

    public void Remove(int Index)
    {
        if (Index > -1) {
            this.DrawingPoints[Index].Delete();
            this.DrawingPoints.RemoveAt(Index);
        }
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected void Dispose(bool IsSafeDisposing)
    {
        if (IsSafeDisposing && (!this.IsDisposed) && (this.DrawingPoints.Count > 0)) {
            foreach (DrawingPoint dp in this.DrawingPoints)
                if (dp != null) dp.Delete();
        }
    }

    public class DrawingPoint
    {
        Pen m_Pen = null;
        Rectangle m_Dot = Rectangle.Empty;

        public DrawingPoint() : this(Point.Empty) { }
        public DrawingPoint(Point newPoint)
        {
            this.m_Pen = new Pen(Color.Red, 1);
            this.m_Dot = new Rectangle(newPoint, new Size(2, 2));
        }

        public Pen DrawingPen { get => this.m_Pen; set => this.m_Pen = value; }
        public Rectangle Dot { get => this.m_Dot; set => this.m_Dot = value; }
        public void Delete()
        {
            if (this.m_Pen != null) this.m_Pen.Dispose();
        }
    }
}

这就是它的工作方式,在需要时更改其属性:

【讨论】:

  • 绘制点就像一个魅力。我只是在更改图片框中的图像时遇到问题。我将 myPoints.Dispose() 偷偷带入我更改图片的方法中。当我在运行时调用 Dispose myPoints 方法时,它也会中断
  • @Eric Lopez-Reyes 好吧,实现的Dispose() 方法是在您需要销毁您的点集合时调用的(当Form 关闭时),以避免泄漏GDI 资源(Pen 对象)。或者当您删除 1 个元素时。您需要一个 .Clear() 方法(如在 List&lt;&gt; 对象中使用的那样)来清空列表。我没有实施(时间不足),但我同意它应该在那里。我将修改该类以包含一个清除列表的方法,因此,当您更改图片时,您不会携带旧的点(您也可以处理对象并创建一个新的)。
  • 感谢您的帮助,我会看看是否可以在此期间解决它
  • @Eric Lopez-Reyes 我在 Main 类 (MyPoints.Clear()) 中添加了一个 Clear() 方法。这将处理点列表并创建一个新点。然后,您可以添加一个新的 PictureBox.Image 并重新启动:MyPoint.Clear(); pictureBox1.Image = [New Image]; 并从头开始绘制。
【解决方案2】:

基本上你必须使用 GDI+

查看以下代码:

    private void pictureBox1_Click(object sender, EventArgs e)
    {
        Graphics g = Graphics.FromImage(pictureBox1.Image);
        Pen p = new Pen(Color.Red, 3);

        var cursorPosition = pictureBox1.PointToClient(Cursor.Position);
        g.DrawEllipse(p, cursorPosition.X, cursorPosition.Y, 15, 15);

        MyCircles.Add(cursorPosition);
        pictureBox1.Refresh();
    }


    List<Point> MyCircles = new List<Point>();

    private void pictureBox1_DoubleClick(object sender, EventArgs e)
    {
        foreach (var item in MyCircles)
        {
            MessageBox.Show($"One circle was created: X:{item.X}, Y:{item.Y}");
        }
    }

MyCircles 列表仅在您想存储圈子以稍后用圈子重新显示图像时,双击是使用它的示例(我的意思是持久性目的,因为圈子在您关闭之前不会离开图像你的应用程序)。检查其他 g 方法来绘制线条、矩形或其他任何东西。 (使用 System.Drawing 命名空间)

【讨论】:

    【解决方案3】:

    我想出了一个简单的解决方案来解决我的问题 我做了一个矩形列表:

            List<Rectangle> rects = new List<Rectangle>();
    

    并通过点击添加矩形:

            private void pictureBox1_Click(object sender, MouseEventArgs e)
            {
                 rects.Add(new Rectangle(e.Location, new Size(4,4)));
            }
    

    并画了点:

            private void pictureBox1_Paint(object sender, PaintEventArgs e)
        {
            foreach (var rect in rects)
            {
    
                e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
                e.Graphics.DrawEllipse(magenta,rect);
            }
        }
    

    并添加了使用rects.Clear()清除图纸的方法

    【讨论】:

      猜你喜欢
      • 2019-03-22
      • 1970-01-01
      • 1970-01-01
      • 2022-01-16
      • 1970-01-01
      • 2011-04-23
      • 1970-01-01
      • 2012-08-28
      • 1970-01-01
      相关资源
      最近更新 更多