views:

598

answers:

7

Hello :)

Is there a way to double-buffer the common controls? Currently when they resize they flicker. A lot.....

EDIT: If it helps, it is a bunch of button controls and a few edit controls, all sitting on top of a tab control. The Tab control redraws itself, then the buttons redraw themselves. When the buttons redraw, they flicker.

EDIT2: Here's an example of the problem I'm having: http://billy-oneal.com/Lobfuscator.exe

A: 

indeed,

someone posted an answer for this on one of my posts a while ago. Check it out: Here

and be sure to upvote him for being awesome.

The code is C#, hopefully there is a simple translation.

Jrud
No. Controls in .NET have nothing to do with controls in Win32.
Billy ONeal
you didn't say anything about it being win32 when you wrote the question. and Pascal Couq added the tags after I posted.
Jrud
And if you notice the link, it goes to the Win32 common controls page. I also note that .NET doesn't call them "common controls".
Billy ONeal
Additionally (to Jruds comment) the solution provided on the linked page actually sets WS_EX_COMPOSITED... the very solution everyone else gave... Since the OS is windows, and it's not a common controls issue, but rather an issue with how windows redraws, his suggestion was valid...
Jason D
A: 

Without knowing exactly what you're doing, I assume you're using either MFC or Win32 C for this.

You probably want to do the resize on WM_SIZE message. I'm not sure where you're resizing the controls, but I think you're doing it while it's being resized, which is why it's causing the flicker.

Also, I'm thinking but I don't know, you could probably use the SetWindowPos function, and for the uFlags, have SWP_NOREDRAW. Though I'm not sure how great this would work for common controls.

Daniel
Tab controls (my window is essentially one big tab control) need to be redrawn then resized. That's why I need the double buffer in the first place.
Billy ONeal
A: 

You can create a memory device context, MemDC at the very start. Draw everything into the MemDC, then when the window recieves a WM_PAINT message or is invalidated, copy the MemDC to the real DC by bit blitting.

I remember reading up the technique by Herbert Schildt in his book a few years back (Windows 98 Programming from the Ground Up). In that way, all the redrawing is faster as you blit the memory dc to the real dc. But the one big gotcha, was how big the memory dc you want to use! But he showed how to do it. There is a code download for all of the chapters in that book published by Osborne McGraw Hill.

Hope this helps, Best regards, Tom.

tommieb75
Yes, but that doesn't help me because I'm not the one doing the drawing. The common control is supposed to be doing that. I don't get sent WM_PAINT messages for the child controls.
Billy ONeal
"Big" has changed over the years. A 1920x1200 full screen is only 7MB.
Mark Ransom
Don't know where you get that Math Mr. Ransom. 1920x1200x32 is 737280000 bits, or 87.89MB
Billy ONeal
I multiply 1920*1200*3, my answer is MegaBytes not Megabits.
Mark Ransom
But that would be four bytes for each pixel (assuming 32 bit color), 1920*1200*4 ~= 9 MB
Sune Rievers
Sune Rievers: We're both idiots. Thanks :)
Billy ONeal
+1  A: 

Larry Osterman recently blogged about this subject; you might find some interesting details there.

Aaron Klotz
I'd rather not have to completely re implement the win32 tab control if I can avoid it.
Billy ONeal
But the key observation there is that the underlying control (Tab control in your case) is causing its children to redraw. Double buffering the individual controls won't help. You either need to make sure they don't get invalidated, or you need a way to buffer all the drawing to the window. Osterman's original approach was to buffer with a WM_PRINTCLIENT hack, but that led to other problems. His final solution didn't involve reimplementing the entire control, just the painting, which is mostly a couple of function calls.
Adrian McCarthy
The tab control is quite a bit more complicated than the groupbox. It's not "just painting" to get it working correctly.
Billy ONeal
A: 

You're not using WS_EX_TRANSPARENT, are you? That will cause underlying windows to be painted before the controls, and when the bottom window erases you get flicker.

Mark Ransom
I don't even know what that is.
Billy ONeal
+1  A: 

Look at using WS_EX_COMPOSITEDand WS_EX_TRANSPARENT styles. They provide doublebuffering, altough WM_PAINT will be called when the underlying bitmap is finished drawing, since it draws child controls from bottom to top, so you can paint only in your window procedure. I've used it in the past and work pretty well.

Set your top-level window (container) to extended style WS_EX_COMPOSITED and your child windows with WS_EX_TRANSPARENT. Also, remember to define:

#define WINVER 0x501

See CreateWindowEx for information on the composited style. This also makes possible to do perpixel transparency on child windows.

UPDATE

What about usign WM_PRINTCLIENT to transfer the client area to a bitmap on a DC and blit all the client area as a whole?

http://blogs.msdn.com/larryosterman/archive/2008/08/27/larry-s-new-favorite-windows-message-wm-printclient.aspx

Hernán
I'll look into it. Might just get the checkmark.. I just need to ensure it works. Unless someone comes up with a solution that works on Win2k....
Billy ONeal
Hmm... didn't work. Still flickers. It seems it's double buffering each individual child control individually, but not the child controls themselves as a whole. This, controls underneath the tab control still flicker :(
Billy ONeal
Sorry.Are you using WS_CLIP_SIBLINGS and WS_CLIPCHILDREN styles?
Hernán
I've updated my answer. Check that, I never used WM_PRINTCLIENT but may help you.
Hernán
More flicker-free drawing techniques http://www.catch22.net/tuts/flicker
Hernán
Don't forget Larry's followup post, Herman, where he explains that WM_PRINTCLIENT was an ugly hack that was only masking the problem (while causing others), rather than actually fixing the flicker. http://blogs.msdn.com/larryosterman/archive/2009/09/16/building-a-flicker-free-volume-control.aspx
Ian Boyd
I didn't know there was a `WS_CLIPSIBLINGS` style -- I was only using `WS_CLIPCHILDREN` which was ineffective because the child controls were not children of the tab control, they were children of my window. That seems to have fixed the issue with the tab control. (So if nobody answers my question you're getting the bounty on this) However, any static controls I have still flicker when resized -- I suspect this is an issue with static controls and I'd still like to be able to double buffer them if possible...
Billy ONeal
A: 

We use WTL::CDoubleBufferImpl mix-in for that purpose. We even draw stuff with GDI+ over. Zero flickering.

Usage is pretty simple: you just public-ly inherit from WTL::CDoubleBufferImpl<YourClass>, and chain it in the ATL message map.

Ivan Krechetov
Where does the WTL namespace come from?
Billy ONeal
Ivan Krechetov