views:

231

answers:

2

I have an application 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,

+1  A: 

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).

Jeff Yates
+1  A: 

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.

MSalters