How to draw small dot on every click of the mouse in WinForms PictureBox

北城以北 提交于 2019-12-11 19:31:54

问题


I have a WinForms program where the user clicks on a PictureBox control.
I want a small red dot (a few pixels across) every time the user clicks.
I also don't want any of the previous dots to go away.

I know I will need a generic list of ellipses and rectangles, but am not sure how to execute this. How would I go about doing this?

In my program a pictureBox1_Click method handles mouse click events and returns the position of the clicks.
A pictureBox1_Paint method handles the graphics to be drawn on these points.


回答1:


You have to create a container that can reference the Points collection and add one point to the collection each time you click on a paint-able Control.

Maybe, you want to also create different kinds of drawing points, based on some conditions or requirements.
Thus, you need to store also these extra properties, not just a point coordinate.
If so, you need a specialized object that can expose these properties when needed.

So, here's a custom Class object with some simple properties, that lets you define a Point's Color and Size. For each of its Points collection.
It also implements the IDisposable interface, because we need to create a Pen object for each Point we draw. And a Pen object needs to be disposed (implements IDisposable).

To perform the drawing, you just need to call Control.Invalidate() (pictureBox1.Invalidate() in the example). This causes the repainting of the invalidated parts of the control, raising the OnPaint() event.
Each point (that needs to be repainted) is drawn using e.Graphics.DrawEllipse()

You can test it this way:

With predefined properties, using just a Mouse pointer coordinate:

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

With specific properties when something different is needed:

With a size of 8x8 pixels
newPoint.Dot = new Rectangle(e.Location, new Size(8, 8)));

With an orange Pen of 2 pixels in size
newPoint.DrawingPen = new Pen(Color.Orange, 2);

Add this new Point to the collection
myPoints.DrawingPoints.Add(newPoint);

EDIT:
Adden a Clear() method to the Main object, used to Dispose() the current list of Points and create a new, empty, List:
MyPoints.Clear();

Sample implementation:

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

The Point objects collection Class container:

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

This is how it can work, changing its properties when required:





回答2:


Basically you must use GDI+

Check the code bellow:

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

The MyCircles List is only if you want to store the circles to reshow the image with the circles later, and the doubleclick is a sample of using it (i mean persistency purposes, because the circles will not leave the image until you close your app). Check other g methods to draw lines, rectangles or whatever. (Uses System.Drawing namespace)




回答3:


I came up with a simple solution for my problem I made a list of rectangles:

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

And added rectangles with ever click:

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

And painted the points:

        private void pictureBox1_Paint(object sender, PaintEventArgs e)
    {
        foreach (var rect in rects)
        {

            e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
            e.Graphics.DrawEllipse(magenta,rect);
        }
    }

And added a method for clearing drawings with rects.Clear()



来源:https://stackoverflow.com/questions/52599453/how-to-draw-small-dot-on-every-click-of-the-mouse-in-winforms-picturebox

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