views:

550

answers:

2

When drawing child controls containing bitmaps with per-pixel alpha channels, we are getting quite a lot of flickering whenever they need to be redrawn. The actual blending is working correctly. I've found a lot of info about reducing flicker (such as this question or this site), but I can't seem to find anything that applies specifically to this situation.

For example, I've got a button with a few different bitmaps that are alpha blended and blitted to the window, depending on the state of the button. When their state changes and I need to draw a different bitmap, I need to redraw the background first, or else it blends with pixels left over from the previous state's bitmap. This is where I am getting some flickering, where I get a bit of the background tearing in occasionally.

The problem is made more complicated by having the top-level parent windows drawing a bitmap background, rather than a solid color, along with the possibility of having child controls overlapping; just multiplying the underlying color into the child's bitmap is out of the question, as is using WS_CLIPCHILDREN.

Since the windows have a bitmap background, I'm returning true on WM_ERASEBKGND, to avoid drawing a color that will just be overwritten.

Of course, double buffering would seem to solve all of this, but I have not been able to get it to work right. I've set WS_COMPOSITED for top-level windows, and WS_TRANSPARENT for child windows. When it comes time to redraw a child window with a new bitmap, I am having a few issues (most likely from me not understanding how the draw order is working in this situation):

  • If I call InvalidateRect() and pass the child handle, the child window is indeed redrawn, but the background is not redrawn, and so the pixels accumulate on top of each other, blending together.
  • If I call InvalidateRect() and pass in the parent handle, with a rectangle consisting of the child window's dimensions, the background is redrawn, but the child window is not.
  • If I do both of the above, then the background is redrawn as well as the child window, and it looks exactly as I'd want -- except that by doing so, I've managed to make it flicker again (which isn't really surprising, since it seems terribly hackish to call InvalidateRect() twice like that, as I'd guess that each call is probably causing the buffers to flip, which defeats the purpose).

What I've come to conclude is that I don't really understand how I need to modify my program to handle double buffering, or if double buffering will even help with this situation. I feel like it definitely would, but I don't quite understand how I need to modify things to get everything to play nicely again.

+1  A: 

This could be completely off base - my gui days were a long long time ago...

But couldn't you just precompute the blends for your different states? I assume your button can be enabled/disable and up/down, so that's only 4 combinations. Why not precompute the combined bitmaps?

Or is the problem the interaction of already combined bitmaps with the existing state?

Mike G.
Something like that could work if I were to automate it per instance, since the same source bitmap may be on top of any number of different backgrounds. It wouldn't help with windows that will move (may need to resort to layered windows for that), but it would solve the occasional flicker on buttons.
Doug Kavendek
+1  A: 

Are you using layered windows? If not maybe try it out.

Also for double buffering consider this technique.

Valentin Galea
I'm using layered windows for very specific uses right now, though I think I may be able to apply them to a few specific cases where possible. Also, not using MFC, but manually doing some double buffering is certainly another option.
Doug Kavendek