user6425922
user6425922

Reputation: 47

Drawing a new circle bitmap at the click location while preserving previously drawn circles

I am trying to draw circles using Bitmap.

Each time I click the mouse, the circle I previously drew is moved to the new position.

What I want to happen is: Each time I click the mouse, a new circle is created/drawn at the position I clicked and all previously drawn circles remain without moving.

I am working with the following code:

using System;
using System.Drawing;
using System.Windows.Forms;

namespace multirectangle
{
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
        SetStyle(ControlStyles.AllPaintingInWmPaint, true);
    }
    Bitmap background;
    Graphics scG;

    Rectangle rectangleObj;

    private Point clickCurrent = Point.Empty;
    private Point clickPrev = Point.Empty;


    private void Form1_Load(object sender, EventArgs e)
    {
        background = new Bitmap(Width, Height);
        rectangleObj = new Rectangle(10, 10, 30, 30);
        scG = Graphics.FromImage(background);
    }

    private void Form1_MouseDown(object sender, MouseEventArgs e)
    {
        clickCurrent = PointToClient(Cursor.Position);
        clickPrev = clickCurrent;
        if (clickPrev == Point.Empty) return;
        rectangleObj.X = clickPrev.X - rectangleObj.Height / 2;// +radius; 
        rectangleObj.Y = clickPrev.Y - rectangleObj.Width / 2;
        Refresh();
    }

    protected override void OnPaint(PaintEventArgs pe)
    {
        pe.Graphics.DrawImage(Draw(), 0, 0);

    }
    public Bitmap Draw()
    {
        Graphics scG = Graphics.FromImage(background);
        Pen myPen = new Pen(System.Drawing.Color.Red, 3);
        scG.Clear(SystemColors.Control);
        scG.DrawEllipse(myPen, rectangleObj);
        return background;

    }
}
}

Upvotes: 1

Views: 619

Answers (4)

Alexander Petrov
Alexander Petrov

Reputation: 14231

Please try this

Rectangle rectangleObj;
Bitmap background;
Graphics scG;
Pen myPen;

private void Form1_Load(object sender, EventArgs e)
{
    rectangleObj = new Rectangle(10, 10, 30, 30);
    background = new Bitmap(Width, Height);
    scG = Graphics.FromImage(background);
    myPen = new Pen(Color.Red, 3);

    BackgroundImage = background;
}

private void Form1_MouseDown(object sender, MouseEventArgs e)
{
    var point = PointToClient(Cursor.Position);

    rectangleObj.X = point.X - rectangleObj.Height / 2;
    rectangleObj.Y = point.Y - rectangleObj.Width / 2;

    scG.DrawEllipse(myPen, rectangleObj);
    Refresh();
}

OnPaint and Draw methods removed. As well as clickCurrent and clickPrev fields.

When you change the form size (for example, maximize it), Bitmap and Graphics remain the same, so you get this effect. To avoid this, you need to add the event handler

private void Form1_SizeChanged(object sender, EventArgs e)
{
    background = new Bitmap(Width, Height);
    scG = Graphics.FromImage(background);
    BackgroundImage = background;
}

Note that each time you resize the form, all previously drawn is erased. If this is undesirable, a different approach is needed for drawing. Let me know, I will give another example.

Upvotes: 1

Ryan
Ryan

Reputation: 313

Your English was a little confusing. If I'm understanding your problem correctly, right now the only thing that's being drawn is the new circle where the click was, and you want all the old ones to persist as well? In which case, there are two options:

  1. Don't clear the bitmap before you draw. scG.Clear(SystemColors.Control); will clear the bitmap you just drew. If you remove that line and don't clear the bitmap, then the next time you click, it will then draw the new ellipse right on top of the last bitmap.
  2. If you want a fresh drawing/bitmap everytime, you would need a list of your rectangleObj . Each time you click, you add that point to your rectangleObj collection. Then in your draw method, you would iterate through the collection and draw all of them.

Upvotes: 2

pparas
pparas

Reputation: 549

Swap the position of the following statements

clickCurrent = PointToClient(Cursor.Position);
clickPrev = clickCurrent;

I think you are assigning the clickCurrent to clickPrevious after you initialize clickCurrent. It needs to be the other way.

Upvotes: 1

Frecklefoot
Frecklefoot

Reputation: 1692

I notice a few things. First, in Form1_MouseDown(), you have this:

clickCurrent = PointToClient(Cursor.Position);
clickPrev = clickCurrent;

You are overwriting the old position (clickPrev) before you even save it. If you want to keep both positions, you should put them in a simple structure, like a List. When you get a new point, just Add() it to the list. Then, in your Draw() routine, loop over all the elements in the list and draw them all.

If you just want two positions--and only two--just swap your statements like this:

clickPrev = clickCurrent;
clickCurrent = PointToClient(Cursor.Position);

And you'll have to allocate another rectangle object for the drawing, although it would make more sense to take care of this in the Draw() routine.

Upvotes: 1

Related Questions