views:

64

answers:

2

Hi,

I've got a Windows Form that circulates through images which are displayed on the form as a slideshow. The way I'm doing this is to have a Panel control the size of the form it resides in, and add an event handler that draws an Image object that exists in memory.

void panel_Paint(object sender, PaintEventArgs e)
{
  if (_bShowImage)
  {
    Point leftCorner = new Point((this.Bounds.Width / 2) - (_image.Width / 2), (this.Bounds.Height / 2) - (_image.Height / 2));

    e.Graphics.DrawImage(_image, leftCorner);

    _bShowImage = false;
  }
}

When a new Image is loaded and referenced by _image, I'm forcing the Panel to redraw:

_bShowImage = true;
_panel.Refresh();

Immediately afterwards, the image is disposed and the dereferenced from the global variable:

_image.Dispose();
_image = null;

I've seen that it works for a while, say 5 iterations, then the panel_Paint() handler is not being called. I'm using 2-3 JPG's for the display and I know they're not corrupted as they are shown fine for the first x times. I've put debug lines around the Refresh() method of the panel which execute fine. It's as if the call to the handler has been dropped. Has anyone encountered this problem before?

A: 

Hello!

Wouldn't it be smarter to put your pictures in a picture box and loop through them in that way, so that you don't force a repaint on the whole window each time?

just a thought...

Tony

Tony
I used a PictureBox at first but it would present the same problem so I decided to do it myself.
FrancisCastiglione
+1  A: 

This is so completely backwards. Either you use a paint event handler like now. It's just fine (I say it's better than a picturebox) but then you need to drop that _bShowImage and _image.Dispose stuff. You should instead dispose the _image before you power it up with a new one. But not until that.

Or, if you absolutley must dispose the _image right after it's painted, then you should instead use Panel.CreateGraphics to get a Graphichs object you can use to immediately draw the _image and drop the event.

As it stands - it is just darn confusing. Also: .Invalidate() is what you almost always want -not .Refresh(). That's just something that got stuck in many minds since the VB6 era.

danbystrom
I put the Paint event handling on one side for now and went for that suggestion. Now at least we're getting somewhere as I'm getting an actual exception: System.Runtime.InteropServices.ExternalException: A generic error occurred in GDI+. at System.Drawing.Graphics.CheckErrorStatus(Int32 status) at System.Drawing.Graphics.DrawImage(Image image, Int32 x, Int32 y) at System.Drawing.Graphics.DrawImage(Image image, Point point) I thought it might be a memory leak but I dispose of the image. Also, the Graphics object is a global one so I only dispose of it once at the end.
FrancisCastiglione
This sounds backwards too - either you keep it global, dispose it and make sure you immediately set it to null so that you at least get a null reference exception if you try to use it. Or you make it local. Having "global" disposed references lying around is good for nothing. You can almost always get away with forgetting a .Dispose(). But never with disposing something that is still in use. At least for your bug tracking for now: drop the .Dispose().
danbystrom