1
votes

I've been working on a simple graphics project where I can draw shapes using button and edit them (Resize and other stuffs). I've been able to draw different shapes, but my problem is that I cannot draw the same shape again. It only updates the parameter of the previous same shape.

For example, I tried to draw a rectangle and then I want to draw again in a different size, the rectangle changes it size rather than creating a new one.

Here's my code:

Shape Class

class ShapeClass
{
    public int x { get; set; }
    public int y { get; set; }
    public int width { get; set; }
    public int height { get; set; }
    public Pen color { get; set; }
    public string Shape { get; set; }
 }

Draw Class

class Draw:ShapeClass
    {
    public void DrawRectangle(PaintEventArgs e)
        {
        e.Graphics.DrawRectangle(color, new Rectangle(x, y, width, height));
    }
    public void DrawSquare(PaintEventArgs e)
    {
        e.Graphics.DrawRectangle(color, new Rectangle(x, y, width, height));
    }
    public void DrawCircle(PaintEventArgs e)
    {
        e.Graphics.DrawEllipse(color, new Rectangle(x,y,width,height));
    }
    public void DrawEllipse(PaintEventArgs e)
    {
        e.Graphics.DrawEllipse(color, new Rectangle(x, y, width, height));
    }

Paint Events

    public void PaintRect(object sender, PaintEventArgs e)
    {
        //Calls Draw class and sets the parameters of the Shape.
        Draw d = new Draw();
        d.x = rX;
        d.y = rY;
        d.width = rW;
        d.height = rH;
        rC = new Pen(Color.Red, 2);
        d.color = rC;
        d.DrawRectangle(e);
    }
    public void PaintSquare(object sender, PaintEventArgs e)
    {
        //Calls Draw class and sets the parameters of the Shape.
        Draw d = new Draw();
        d.x = sX;
        d.y = sY;
        d.width = sW;
        d.height = sH;
        d.color = new Pen(Color.Red, 2);
        //d._Rectangle.Add(new Rectangle(sX,sY,sW,sH));
        d.DrawSquare(e);
    }
    public void PaintCircle(object sender, PaintEventArgs e)
    {
        //Calls Draw class and sets the parameters of the Shape.
        Draw d = new Draw();
        d.x = cX;
        d.y = cY;
        d.width = cW;
        d.height = cH;
        d.color = new Pen(Color.Red, 2);
        d.DrawCircle(e);
    }
    public void PaintEllipse(object sender, PaintEventArgs e)
    {
        //Calls Draw class and sets the parameters of the Shape.
        Draw d = new Draw();
        d.x = eX;
        d.y = eY;
        d.width = eW;
        d.height = eH;
        d.color = new Pen(Color.Red, 2);
        d.DrawEllipse(e);
    }
1
I think we need to see the definition of ShapeClass to see how you define the various location and size parameters. - Corey
Edited the body. - user10236999
I'm obviously missing something. How are you defining cX, cY, cW and cH? - Corey
Every time a Paint event is raised, everything you have previously drawn is erased. If you want multiple shapes drawn then you have to store those shapes in a list at class level and then draw everything in that list on each Paint event. You should have one Paint event handler that draws every item in the list and then adding a new shape would be a case of adding an item to that list and then forcing a repaint by calling Refresh. - jmcilhinney
The fact that you can't write the correct code seconds after being told what to do is no indication that you can't do it. Put some thought into it. Make your best attempt and then, if it doesn't work, update your question with the new code and we can help further. In short, always do what you can for yourself first and only ask for more help when you actually get stuck. Assuming you can't do it and asking others to write your code for is not the way to get better at writing code yourself. Failure is an integral part of learning so the potential for failure is not a reason not to try. - jmcilhinney

1 Answers

0
votes

Let's look at your PaintCircle event handler for a moment:

public void PaintCircle(object sender, PaintEventArgs e)
{
    //Calls Draw class and sets the parameters of the Shape.
    Draw d = new Draw();
    d.x = cX;
    d.y = cY;
    d.width = cW;
    d.height = cH;
    d.color = new Pen(Color.Red, 2);
    d.DrawCircle(e);
}

Fairly straight-forward, but it looks very much like you have a set of values that are defined once on the form: cX, cY, cW and cH. You have similar variables in the other Paint... methods.

Almost certain that what's happening is that you are adjusting those variables and redrawing the canvas. This will generally wipe the existing content and redraw completely, which means that your existing image will be removed and your 'new' shape will be the one that is drawn.

There are a couple of ways to get around this:

  1. Make the image persistent

You can create a System.Drawing.Bitmap object the right shape for your canvas, do all of your drawing on the Bitmap and then update the display.

The down-side of this is that you can't go back and change the existing objects if you want to. Once you draw on the image it is permanently altered with the new shape.

If you're going this way you should probably give some thought to using multiple Bitmap images so you can undo by bringing a prior image from your list. When you start a draw operation copy the current Bitmap and put the copy in your undo list. To undo, pull the last item from that list and replace your working Bitmap with it. Don't forget to tidy up your undo list to make sure you don't use all of memory.

  1. Maintain a list of objects and re-draw the whole list as required

For this you will need to build some more interesting Shape classes.

Here's a quick sample...

public abstract class Shape
{
    public int X { get; set; }
    public int Y { get; set; }
    public int Width { get; set; }
    public int Height { get; set; }
    public Pen LineColor { get; set; } = Pens.Red;
    public Brush FillColor { get; set; } = null;

    public abstract void Draw(Graphics g);
}

public class EllipseShape : Shape
{
    public override void Draw(Graphics g)
    {
        if (FillColor != null)
            g.FillEllipse(FillColor, X, Y, Width, Height);
        g.DrawEllipse(LineColor, X, Y, Width, Height);
    }
}

public class RectangleShape : Shape
{
    public override void Draw(Graphics g)
    {
        if (FillColor != null)
            g.FillRectangle(FillColor, X, Y, Width, Height);
        g.DrawRectangle(LineColor, X, Y, Width, Height);
    }
}

... and so on.

On your main form you can add a List<Shape> to hold your shapes, then in the OnPaint event for the canvas - whatever type of canvas you're using - you do this:

private void MainForm_Paint(object sender, PaintEventArgs e)
{
    var g = e.Graphics;
    foreach (var shape in shapeList)
        shape.Draw(g);
}