Eddy 070792
Eddy 070792

Reputation: 11

Create rectangle drawing inside the picturebox

After button click event I want the program to draw a rectangle inside a picturebox. I don't know how to do that. So far I made only a rectangle outside of picture box like this. Afterwards I want to implement a flood fill algorithm to fill the rectangle with a color. That's why I have to have those bitmaps there.

namespace howto_floodfill
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        // The background image.
        private Bitmap bm;
        private Bitmap32 bm32;

        // Make a rectangle

        private void button1_Click(object sender, EventArgs e)
        {
            bm = new Bitmap(ClientSize.Width, ClientSize.Height);
            using (Graphics gr = Graphics.FromImage(bm))
            {
                gr.Clear(Color.Silver);
                gr.DrawRectangle(Pens.Black, 5, 5, 100, 60);
            }

            bm32 = new Bitmap32(bm);

            this.BackgroundImage = bm;
        }

    }
}

Upvotes: 1

Views: 9643

Answers (3)

Stuart Smith
Stuart Smith

Reputation: 133

You can use the control.CreateGraphics() method invoked from your picturebox.

namespace WindowsFormsApplication_Test
{
    public partial class Form1 : Form
    {
        private Bitmap bm;

        public Form1()
        {
            InitializeComponent();
            bm = new Bitmap(pB.ClientRectangle.Width, pB.ClientRectangle.Height);
        }

        private void btn_Click(object sender, EventArgs e)
        {
            Graphics gF = pB.CreateGraphics();
            gF.Clear(Color.Silver);
            gF.DrawRectangle(Pens.Black, 5, 5, 100, 60);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Graphics gF = Graphics.FromImage(bm);
            gF.Clear(Color.Silver);
            gF.DrawRectangle(Pens.Black, 5, 5, 100, 60);
            pB.Image = bm;
        }

    }
}

btn_click() is an example of getting the graphics context from the control and drawing directly.

Form prior to clicking Form prior to clicking...

Clicking the button will draw on the control directly - note that by default it gives you the clientRectangle portion of the control, which is nice...

Form after clicking Clicking on the button gives you this.

any event that invalidates the control Now I resized the form.

Unfortunately, drawing on the form this way makes you responsible for redrawing your data any time the window is invalidated.

You can also just set the Image property of the form to be your private bitmap and then the framework handles redrawing for you. This is shown in the button1_Click() method.

enter image description here

You can still draw directly on the control if you wish, but you'll need to hook into the control events and redraw when the form does. For example, adding a flag as a private bool to the form class, overriding the OnPaint method, and adding code to your button event to swap the flag. Rather than duplicating the drawing code in the button event, you can just flip the flag and call this.Invalidate();

public partial class Form1 : Form
{
    private Bitmap bm;
    private bool bDrawn = false;

    public Form1()
    {
        InitializeComponent();
        bm = new Bitmap(pB.ClientRectangle.Width, pB.ClientRectangle.Height);
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);

        if (bDrawn)
        {
            Graphics gF = pB.CreateGraphics();
            gF.Clear(Color.Silver);
            gF.DrawRectangle(Pens.Black, 5, 5, 100, 60);
        }
    }
    private void btn_Click(object sender, EventArgs e)
    {
        //Graphics gF = pB.CreateGraphics();
        //gF.Clear(Color.Silver);
        ///gF.DrawRectangle(Pens.Black, 5, 5, 100, 60);
        bDrawn = true;
        this.Invalidate();
    }

Upvotes: 1

adv12
adv12

Reputation: 8551

You can set a Paint event handler for the PictureBox that will allow you to do drawing over the top of the PictureBox contents:

public partial class Form1 : Form
{

    private bool _drawRectangle = false;

    public Form1()
    {
        InitializeComponent();
        pictureBox1.Paint += new PaintEventHandler(this.pictureBox1_Paint);
    }

    private void pictureBox1_Paint(object sender, PaintEventArgs e)
    {
        if (_drawRectangle) {
            Graphics g = e.Graphics;
            // use g to do your drawing
        }
    }
}

Just set _drawRectangle to true in your button click handler and call pictureBox1.Invalidate(). Doing your drawing in the Paint event handler guarantees that whenever the PictureBox is redrawn (say, because another window was over it), your rectangle gets drawn as well.

This will let you draw a rectangle over the PictureBox's contents. Rather than a flood fill algorithm, have you considered just using FillRectangle?

If you really want to do a flood fill, you'll have to work with an image as you're already doing, so you can read pixels from the image to know if a boundary has been reached. Then you could set the PictureBox's Image property with the resulting bitmap. (In this case, it wouldn't be necessary to do the graphics work in the Paint event handler, since the PictureBox will make sure its Image is drawn on every paint.)

Upvotes: 3

Mehrzad Chehraz
Mehrzad Chehraz

Reputation: 5137

Assign the created bitmap to the Image property of the picture box. Now you can draw whatever you want on the bitmap, and then manipulate it's data.

namespace howto_floodfill {
    public partial class Form1 : Form {
        private Bitmap bitmap;
        public Form1() {
            InitializeComponent();
            this.bitmap = new Bitmap(100, 100);
            this.pictureBox1.Image = this.bitmap;
        }

        // Make a rectangle
        private void button1_Click(object sender, EventArgs e) {
            if (this.bitmap != null) {
                this.bitmap.Dispose();
            }
            this.bitmap = new Bitmap(ClientSize.Width, ClientSize.Height);
            using (Graphics gr = Graphics.FromImage(bitmap)) {
                gr.Clear(Color.Silver);
                gr.DrawRectangle(Pens.Black, 5, 5, 100, 60);
            }
            this.pictureBox1.Image = this.bitmap;
        }

    }
}

Note that you may not need to re-create the bitmap each time if it has a fixed size.

Upvotes: 0

Related Questions