Why paint messages get lost even after calling UpdateWindow()?
I have an appl开发者_开发技巧ication with following windows hierarchy:
W1
-W2 (Child of W1)
- W3 ( Child of W2)
--------------------|
| W1|------------| |
| |W2 |------| | |
| | |W3 | | |
| | |------| | |
| |------------| |
|-------------------|
When certain event happens in W2, I call UpdateWindow
:
W2::onCertainEvent()
{
Invalidate(NULL);
UpdateWindow();
}
The OnPaint
handling of W2 looks like this:
W2::onPaint()
{
//W2 logic goes here
W3.Invalidate(NULL); //So that paint messages are given to W3
}
But some times the paint messages are getting lost in W2. Though UpdateWindow
gets called, there is no corresponding OnPaint
() getting called.
If I add a property WS_EX_TRANSPARENT
to W1 ( the parent of W2) then always paint messages are received @ W2.
But the problem with adding the WS_EX_TRANSPARENT
flag is that it creates lot of flicker when I resize the window W1.
My Questions are:
1. What is wrong in W2 so that Paint messages are lost?
2. Why adding WS_EX_TRANSPARENT
solves the Paint problem.
3. How do I solve flicker issue if the flag is used.
Thanks,
Flicker
Flicker can be resolved by handing WM_ERASEBKGND
and making sure it does nothing. The flicker can occur because each Window handles this message before every paint to erase the invalid area using its background colour. If you handle it and do nothing, the erase doesn't occur - just make sure your WM_PAINT
handler paints the entire invalidated area or you'll leave artifacts from the previous paint behind.
However, in this case, I believe the flicker occurs because W1 paints itself first, then W2, then W3 on each paint. This suggests that WS_EX_TRANSPARENT
is not the way to fix the problem you're experiencing.
Missing WM_PAINT
It's difficult to know how to track this down. In .NET, this happens because the child windows obscure the entire client area of the control and so the paint message is not propagated through but I believe that's a specific .NET behaviour. If you could provide a sample project or sample code that exhibits the problem, it would be a big help.
In the meantime, you could remove W3 so that W2 is not obscured and see if all your paint messages return. Also, note that CWnd::Invalidate
doesn't take NULL as an option, it takes a BOOL
(TRUE
or FALSE
).
WM_PAINT "messages" are not really messages in the normal sense of the word. They behave much like flags at the end of the message queue of each window. They don't go through the thread message queue, they don't have a position in the windows message queue. They're generated when you try to retrieve a message from the windows message queue, and there are no other messages. At that time, all the different invalidations are considered and one or more (!) WM_PAINT are generated.
The result is that after your W2::onCertainEvent()
the "window invalid" flag will be set. It follows that eventually WM_PAINT
will be called, but the WM_PAINT that is generated then will not be exclusively for that "Certain Event".
The historical background is that you don't want to spend too much time painting a window if there were a lot of messages pending, as those are probably just going to invalidate your window anyway. Better get your Model up to date first, and then do the View stuff.
精彩评论