-2

I wanted to make a small animation(simple pics just to see how it worked) and had to do a days research before being able to come up with this:

private void pictureBox1_Click(object sender, EventArgs e)
    {
        for (int imgNum = 1; imgNum <= 5; imgNum++)
        {
            System.Threading.Thread.Sleep(300);
            pictureBox1.Image = (Image)(Properties.Resources.ResourceManager.GetObject(string.Format("Circle{0}", imgNum)));
        }
    }

However when I ran this the program would display the first image, wait 1.2 seconds (the sleep time) and would then proceed to display the last image. I remembered doing an exercise that used Application.DoEvents() for something so I tried that and the pics displayed correctly.

    private void pictureBox1_Click(object sender, EventArgs e)
    {
        for (int imgNum = 1; imgNum <= 5; imgNum++)
        {
            Application.DoEvents();
            System.Threading.Thread.Sleep(300);
            pictureBox1.Image = (Image)(Properties.Resources.ResourceManager.GetObject(string.Format("Circle{0}", imgNum)));
        }
    }

My question is how did Application.DoEvents() make it so that the images displayed. What is the purpose of Application.DoEvents()? Is there a better way to display animations?

And yes I am a beginner.

Poplop
  • 33
  • 1
  • 6

1 Answers1

1

How do I solve the problem?

Use a windows timer control and render the image by capturing the timer events with an event handler that draws the image. This is the way you're supposed to do it, anyway.

What is the deal with DoEvents()?

If you want to know exactly what DoEvents you're in for a heckuva learning curve. It's very very complicated. Here's the shortest summary I could come up with.

You may be surprised to learn this, but you don't actually get to write a windows forms application. It is already written for you. The only thing you can write are event handlers and functions that support them.

All windows forms applications consist of a main thread which runs what is sometimes called the "message loop" or "message pump." Examples of messages are WM_PAINT (which command the application to draw itself) or WM_COMMAND (which is the result of a mouse click or keystroke). The message pump is just a gigantic loop which looks very much like this:

MSG msg;
BOOL bRet;
while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{ 
   if (bRet == -1)
   {
       // handle the error and possibly exit
   }
   else
   {
       TranslateMessage(&msg); 
       DispatchMessage(&msg); 
   }
}        

This loop reads messages from the message queue in a FIFO fashion and makes the calls to handle the messages, including calls to your own event handlers.

While your event handler is running, the event loop is NOT running. This means that your Sleep() statement actually blocks any other events from being processed, including painting the application or handling user input!

The DoEvents command instructs your event handler to yield control to the message pump until it is empty, then returns. Thus if you continually call DoEvents, the application can repaint itself or handle input before your event handler has completed execution.

So instead of Sleep(1000) you can use something like this:

var waitUntil = System.DateTime.Now.AddSeconds(1);
while (System.DateTime.Now < waitUntil)
{
    Application.DoEvents();
}

...which will run the message pump continually until the time interval has passed.

Note: If you were actually to do this, I'd recommend you use a high performance timer instead of System.DateTime. However, you probably should not do this either, unless you are doing something very specific that requires special handling.

Instead, you should use the very common approach of using a windows timer control which is intended for exactly this purpose. The timer control will add WM_TIMER messages to the message queue when the time has expired; these will be dispatched to your timer event handler in due course, all the while letting the application process all the other messages that are firing.

DoEvents() is evil

Also, please note that DoEvents() is considered "evil" in that it introduces threading concerns. Imagine if you event handler is called again before it is finished! Could be trouble.

More information on this topic here

Community
  • 1
  • 1
John Wu
  • 50,556
  • 8
  • 44
  • 80