Graphics over a picturebox aren't showing and if they are they flicker before disappearing

1.7k Views Asked by At

I'm working on a windows forms application and when I'm using the System.Drawing.Graphics on top of a picturebox the graphics either don't appear or appear only momentarily before disappearing.

This is the code that I'm using to set the picturebox (it's a simplified version and still exhibits the behavior)

private void showGraphic()
{
    pictureBox1.Invalidate();
    System.Drawing.Graphics graphics = this.pictureBox1.CreateGraphics();
    SolidBrush semiTransBrush = new SolidBrush(Color.FromArgb(128, 0, 0, 255));
    System.Drawing.Rectangle rect = new System.Drawing.Rectangle(100,100, 50, 50);

    graphics.FillEllipse(semiTransBrush, rect);
}

private void button1_Click(object sender, EventArgs e)
{
    showGraphic();
}

The settings for the picturebox are just the default settings with a picture from a file declared in the properties pane.

I was able to solve this problem by using a timer which was started by the button and then executed the graphic drawing before stopping itself, however this seemed a terrible solution and I wanted to do this a better way, if one exists as that could result in lack of portability to older computers.

Thanks in advance

3

There are 3 best solutions below

1
On BEST ANSWER

You need to register a handler for the PictureBox's Paint method and do your drawing in that method. (Note: use the Graphics object passed in via the PaintEventArgs parameter.) That will guarantee that any time the PictureBox gets redrawn, your drawing code will run as well. Otherwise, you're just drawing over the top of something that will get refreshed for any of a number of reasons.

Once you've registered for the Paint event, anytime you want to repaint, call Invalidate() on the PictureBox and your painting code will run. You can keep track of whether or not your overlay graphics should be drawn via a private boolean member variable.

0
On

When you call pictureBox1.Invalidate() it queues up a message that the picture box needs to be drawn. Before that message gets processed you are drawing an ellipse on top of the current picture. Then message loop then processes the paint message from the invalidate and then repaints itself (which erases your image)

3
On

To make this (old and answered) question more complete I'm adding an alternative solution: sometimes you don't want to redraw your picture every refresh, for example if drawing is complicated and takes time. For these cases, you can try the following approach:

  1. Create a new bitmap in the size of the picturebox.
  2. Draw on bitmap.
  3. Set bitmap as the picturebox Image.

For example:

// create a new bitmap and create graphics from it
var bitmap = new Bitmap(pictureBox1.Width, pictureBox1.Height);
var graphics = System.Drawing.Graphics.FromImage(bitmap);

// draw on bitmap
SolidBrush semiTransBrush = new SolidBrush(Color.FromArgb(128, 0, 0, 255));
System.Drawing.Rectangle rect = new System.Drawing.Rectangle(100,100, 50, 50);
graphics.FillEllipse(semiTransBrush, rect);

// set bitmap as the picturebox's image
pictureBox1.Image = bitmap;

With the code above you can draw everything once and it will survive redraw events.