Drawing rectangle on main form from class

Uberokeer

New member
Joined
Aug 3, 2013
Messages
1
Programming Experience
3-5
Hello, this is My first time posting here. I'm making a 2 dimensional side scrolling game. What i'm doing is making a level editor, and i need a class that represents each type of block for instance: "Dirt" I need a class called dirt(which i have). Inside that class is a function called Run. with the code:
public void run(int Xint, int Yint, PictureBox Drawspace, Bitmap Texture)
        {
            Rectangle DirtBlock = new Rectangle(0, 0, 0, 0);
            Graphics G;
            Bitmap MyTexture = Texture; 
            DirtBlock.X = Xint;
            DirtBlock.Y = Yint;
            DirtBlock.Height = 50;
            DirtBlock.Width = 50;
            G = Drawspace.CreateGraphics();
            G.DrawRectangle(Pens.Black, DirtBlock);
            TextureBrush DrawTexture = new TextureBrush(MyTexture);
            G.FillRectangle(DrawTexture, DirtBlock);
            
        }
Now everything works just fine, except it won't actually draw the graphics. What i'm trying to do is call the function, and then in the function it will draw graphics on the main form which is where the function is originally being called from.
But for some reason it just doesn't work. I know that it's actually calling the function, and getting through it, because I tried putting Application.Exit(); at the end of G.FillRectangle(DrawTexture, DirtBlock); and it closes the program when i call the function(which is what i want). So i have no idea why it doesn't draw. If you know why please tell me. Thanks :D
 
Last edited by a moderator:

jmcilhinney

C# Forum Moderator
Staff member
Joined
Apr 23, 2011
Messages
3,150
Location
Sydney, Australia
Programming Experience
10+
No, no and double no. You should pretty much NEVER be calling CreateGraphics. If you want to draw on a control, which includes forms because they are controls too, then you do so on that control's Paint event. If the control has to draw on itself then you override its OnPaint method and do the drawing there and if you want to draw on a control from outside then you handle its Paint event. In either case, the 'e' parameter provides the Graphics object you use to do the drawing.

So, that class should have properties for the data you're passing in to that method and a method to handle the Paint event of the PictureBox. It should look something like this:
using System;
using System.Drawing;
using System.Windows.Forms;

public class SomeClass : IDisposable
{
    private PictureBox _drawSpace;
    private Bitmap _texture;
    private Point _location;
    
    public PictureBox DrawSpace
        {
            get
            {
                return this._drawSpace;
            }
            set
            {
                if (this._drawSpace != value)
                {
                    if (this._drawSpace != null)
                    {
                        this._drawSpace.Paint -= this.PictureBox_Paint;
                        this._drawSpace.Refresh();
                    }

                    this._drawSpace = value;
                    this._drawSpace.Paint += this.PictureBox_Paint;

                    this._drawSpace.Refresh();
                }
            }
        }

    public Bitmap Texture
        {
            get
            {
                return this._texture;
            }
            set
            {
                if (this._texture != value)
                {
                    this._texture = value;

                    if (this._drawSpace != null)
                    {
                        this._drawSpace.Refresh();
                    }
                }
            }
        }

    public Point Location
        {
            get
            {
                return this._location;
            }
            set
            {
                if (this._location != value)
                {
                    this._location = value;

                    if (this._drawSpace != null)
                    {
                        this._drawSpace.Refresh();
                    }
                }
            }
        }

    private void PictureBox_Paint(object sender, PaintEventArgs e)
    {
        var dirtBlock = new Rectangle(this._location.X, this._location.Y, 50, 50);
        var g = e.Graphics;

        using (var drawTexture = new TextureBrush(this._texture))
        {
            g.DrawRectangle(Pens.Black, dirtBlock);
            g.FillRectangle(drawTexture, dirtBlock);
        }
    }

    private bool isDisposed;

    protected virtual void Dispose(bool isDisposing)
    {
        if (!this.isDisposed && isDisposing)
        {
            if (this._drawSpace != null)
            {
                this._drawSpace.Paint -= this.PictureBox_Paint;
            }
        }

        this.isDisposed = true;
    }

    public void Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }
}
You create an instance of that class and set the Location, Texture and DrawSpace properties. The drawing will then be done automatically as required. Whenever you set one of those properties again, the Refresh method of the PictureBox will be called and that raises the Paint event, thus the new drawing will be done.

To be clear, the reason that you don't see your drawing now is that the PictureBox is repainted every time the Paint event is raised, which can be quite regularly, in which case your drawing just disappears. That's why you have to draw on the Paint event: to re draw everything each time the control is repainted. By handling the Paint event and doing your drawing in the event handler, you ensure that the drawing done and redone every time the control is repainted. By refreshing the PictureBox each time you make a change, you ensure that the drawing updates each time the parameters change.
 
Top Bottom