How to stop a paint event handler function by another event

  • Thread starter Thread starter wasishincar
  • Start date Start date
W

wasishincar

Hi there,

I'm working on a stress test tool for drawing. After start button
clicked, it fires Form_Paint(xxx) event handler to continuous drawing
shapes on screen. Problem is once there is a while loop in the event
handler, so once entering the loop, no other event can capture from
application.

I tried to use a thread but it causes another problem that e.Graphics
will be out of scope, and raise an exception.

Below is my brief of my code. Could any one tell me how to make solve
this problem? Thanks.

private bool bTesting;

private void drawPage(Graphics g)
{
// do something draw...
}

private void Form_Paint(Object sender, PaintEventArgs e)
{
// skip

while(this.bTesting)
{
drawPage(e.Graphics);
}
}
 
I'm working on a stress test tool for drawing. After start button
clicked, it fires Form_Paint(xxx) event handler to continuous drawing
shapes on screen. Problem is once there is a while loop in the event
handler, so once entering the loop, no other event can capture from
application.

I tried to use a thread but it causes another problem that e.Graphics
will be out of scope, and raise an exception.

Below is my brief of my code. Could any one tell me how to make solve
this problem? Thanks.

Yes. Don't use that code.

Your Paint event handler must do exactly one thing: paint the control
_once_ and return immediately. It's very bad to do anything else, and
it's simply awful to have a loop that draws repeatedly.

This is a common error for people unfamiliar with the Windows API. Here's
one of the most recent threads, of many, in the newsgroups I follow
addressing this very question:
<http://groups.google.com/group/micr...read/thread/bfb53115470ebc76/f8704ea42d90042c>

Pete
 
Yes. Don't use that code.

Your Paint event handler must do exactly one thing: paint the control
_once_ and return immediately. It's very bad to do anything else, and
it's simply awful to have a loop that draws repeatedly.

This is a common error for people unfamiliar with the Windows API. Here's
one of the most recent threads, of many, in the newsgroups I follow
addressing this very question:
<http://groups.google.com/group/microsoft.public.dotnet.languages.csha...>

Pete

Thanks a lot, Pete.

After read Bob Powell's GDI+ guide, I have more sense about painting.

Now, I move the loop to a thread, but it failed to call Invalidate()
to update form. I copy the detail exception log below
System.NotSupportedException was unhandled
Message="Chinese words" <- means something like "System can't
display error message due to no resource component" , sorry for my bad
translation.
StackTrace:
$B1w(B Microsoft.AGL.Common.MISC.HandleAr()
$B1w(B System.Windows.Forms.Control.Invalidate()
$B1w(B DisplayTest.FormDisplayStress.StartTest()
Could you give me some suggestion on thread. Thanks in advance.

My second code:
private bool bTesting;

private void buttonStart_Click(object sender, EventArgs e)
{
Thread thread = new Thread(new ThreadStart(this.StartTest));
thread.Start();
}

public void StartTest()
{
while(this.bTesting)
{
this.getSomeShapeConfiguration();
this.Invalidate(); // <-
}
}

private void drawPage(Graphics g)
{
// do something draw...
}

private void Form_Paint(Object sender, PaintEventArgs e)
{
// skip
drawPage(e.Graphics);
}
 
After read Bob Powell's GDI+ guide, I have more sense about painting.

Now, I move the loop to a thread, but it failed to call Invalidate()
to update form. I copy the detail exception log below
System.NotSupportedException was unhandled
Message="Chinese words" <- means something like "System can't
display error message due to no resource component" , sorry for my bad
translation.
StackTrace:
æ–¼ Microsoft.AGL.Common.MISC.HandleAr()
æ–¼ System.Windows.Forms.Control.Invalidate()
æ–¼ DisplayTest.FormDisplayStress.StartTest()
Could you give me some suggestion on thread. Thanks in advance.

I see that Bob's site could be a little more beginner-friendly (and he's
still got at least one bug in one of his samples, that I reported to him
but he hasn't fixed). But, here's an article that sort of addresses this
question:
http://www.bobpowell.net/animation.htm

If you read through it, you'll see he's using the
System.Windows.Forms.Timer class instead of a Thread. In his case, he
wants to draw things at specific intervals, and the Forms.Timer class
specifically ensures that the code executed at those intervals is run on
the correct thread.

In your code, you have the problem that the code calling Invalidate() is
on the wrong thread, thus the exception. Depending on how your
application's animation is supposed to work, you can either modify your
application so that instead of using a Thread, you just call
"getSomeShapeConfiguration()" from a Tick event handler for a Forms.Timer
object, or you can fix the StartTest() method so that it deals with the
cross-thread call correctly.

As an example of the latter:

public void StartTest()
{
while(bTesting)
{
getSomeShapeConfiguration();
Invoke((MethodInvoker)delegate { Invalidate(); });
}
}

Using the Invoke() method causes the anonymous method to be executed on
the GUI thread, avoiding the exception.

Pete
 
I see that Bob's site could be a little more beginner-friendly (and he's
still got at least one bug in one of his samples, that I reported to him
but he hasn't fixed). But, here's an article that sort of addresses this
question:http://www.bobpowell.net/animation.htm

If you read through it, you'll see he's using the
System.Windows.Forms.Timer class instead of a Thread. In his case, he
wants to draw things at specific intervals, and the Forms.Timer class
specifically ensures that the code executed at those intervals is run on
the correct thread.

In your code, you have the problem that the code calling Invalidate() is
on the wrong thread, thus the exception. Depending on how your
application's animation is supposed to work, you can either modify your
application so that instead of using a Thread, you just call
"getSomeShapeConfiguration()" from a Tick event handler for a Forms.Timer
object, or you can fix the StartTest() method so that it deals with the
cross-thread call correctly.

As an example of the latter:

public void StartTest()
{
while(bTesting)
{
getSomeShapeConfiguration();
Invoke((MethodInvoker)delegate { Invalidate(); });
}

}

Using the Invoke() method causes the anonymous method to be executed on
the GUI thread, avoiding the exception.

Pete

Great thanks. I finally use Timer to get this test tool done. : )
 
Back
Top