Click here to Skip to main content
Click here to Skip to main content

CDialogResize based class with no groupbox flicker

By , 3 Nov 2003
 

Introduction

While working on a project recently, I happened to use the WTL CDialogResize mix-in class, along with a dialog that had groupboxes on it. Whenever I resized the dialog, I noticed that the groupboxes exhibited an annoying flicker that really detracted from the overall smooth affect. I poked around CodeProject and Usenet for a solution but could not find anything, so I decided to solve the problem myself. For such an apparently trivial problem, the solution was quite complex, but the end result is a smooth flicker free resize.

Using the code

The problem with groupboxes is that they are the only (common) control which can contain other controls. For that reason, the center region is not painted by the control itself, and nor are two regions on the top edge of the control.

The groupbox depends on the parent to fill these in with the default background colour. When you use a resizing dialog, CDialogResize forces the parent window to have the WS_CLIPCHILDREN style. What this does is exclude all child controls from the parents painting region so that the background is not painted, and flicker is reduced. In most cases this works as the child control paints over its entire owned rectangle, but in the case of the groupbox, this causes problems. The usual way to fix this is to set the WS_EX_TRANSPARENT extended style for groupboxes, which prevents the WS_CLIPCHILDREN styled parent window from excluding the groupbox's background region, allowing the background to paint. While this does work, it creates annoying flicker on resize.

My solution was to render groupboxes myself during background painting, and to use a memory dc to reduce flicker. To do this I enumerate all groupboxes on initialization and clear WS_VISIBLE. This prevents them from rendering themselves. I then build my own valid update region by enumerating all child controls except groupboxes, and fill in that region with the background colour. Last, I enumerate all groupboxes and render them, paying attention to the values of flags BS_LEFT,BS_CENTER,BS_RIGHT and BS_FLAT to ensure they render in exactly the same form as the originals. Font metrics is also accounted for, to make sure the groupboxes top offset is correct. On initialization, the code determines if the user is running XP or greater and if so it renders XP style groupboxes (rounded corner, single line). If not XP, it renders the standard square 3D rect style.

For a few bonuses, I threw it the ability to render XP style groupboxes on W2000/9x (or W2000/9x style on XP) by calling SetXPStyleGroupBoxes(). I also added the ability to set a Minimum and Maximum resize limit. Minimum did exist already, but would default to the current design size of the dialog resource. This is probably a good idea, but if you want you can set it smaller using SetMinTrackSize(). SetMaxTrackSize() allows the setting of a maximum window size. If you do not call this function then the window may be maximized to full screen as normal.

There are a few issues I did not address. By default, W2000/XP will not show accelerator (e.g.: OK) underlines until the ALT key is pressed. My replacement groupboxes do not do this, they always show the accelerator. Also, I only coded for normal text mode groupboxes. I have never used them but there are apparently icon and bitmap groupboxes also. Those are not dealt with, so they should render, but flicker as usual. Personally I've never used those styles in 15 years. Usage of a MemDC slightly slows resizing, as a MemDC is getting created and destroyed on every WM_ERASEBKGND. This is more noticeable the bigger the window client area gets, but on my pc is not bothersome. For the XP groupboxes, I have no idea what standard syscolor they are rendered in. I used COLOR_3DSHADOW but it is not exactly right, but close enough.

Usage is very similar to the standard CDialogResize mix-in class, just replace it with CNoFlickerDialogResize. Thats the only difference. Make sure and include nfresize.h somewhere in the project, and to have atlgdix.h (mentioned below) somewhere in the include path.

#include "nfresize.h"

class CMainDlg : 
    public CDialogImpl<CMainDlg>, 
    public CNoFlickerDialogResize<CMainDlg>
{

From there, you do everything as you would when using the standard CDialogResize, set up a resize map and call DlgResize_Init() in OnInitDialog. Michael Dunn has a very good tutorial article on CDialogResize here, if you want to learn usage. Also in OnInitDialog you can call using SetMinTrackSize() and/or SetMaxTrackSize() if required.

There is no practical use except for demonstration, but the function DisableFlicker(bool) if set to false will return painting to normal windows default, and the flicker will resurface.

Demo App

The demo zip contains a silly app to demonstrate the general effect of the flicker reduction. You can turn anti-flicker on and off, and show groupboxes either as XP style or old-school. Fonts can be changed to show proper font handling. This dialog has a maximum upper size of 800 x 600, so that is also demonstrated.

I used the CMemDC class by Bjarke Viksoe in this project, so I included atlgdix.h in the zip. Kudos to Bjarke for making that excellent add in. Check out his website for more excellent stuff.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

SGarratt
Web Developer
United States United States
Member
Brit living in USA
C++ Windows/Unix developer

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralExcellentmemberYogesh P. Dhakad1 May '07 - 11:35 
Dear SGarratt,
 
I have implemented your CNoFlickerDialogResize<> into our application. Thanks - you get my five.
 
Regards
GeneralClarificationmemberTweety30 Apr '04 - 3:37 
Can you please explain to me why in xp, with no themes, when i add resizing to a dialog with frames, the frames appear white (well, not white, just not drawn, 'cause i can see the "shadows" of "past-drawings Big Grin | :-D )? the only thing i found is to make the frames transparent, but i have a button over the frame, so i make that transparent, too. it's way to much flicker and your (this) class doesn't help AT ALL on my comp with this.
 
/* Peace and love,
 *     Tweety
 */

Generalyou misspelled something...memberTweety29 Apr '04 - 17:16 
i downloaded your source code zip and got the following error:
 
c:\wtl71\Samples\GuidGen\nfresize.h(7) : fatal error C1083: Cannot open include file: 'altframe.h': No such file or directory
 
The lines concerned were:
#ifndef __ATLFRAME_H__
#include
#endif

 
you misspelled atlframe to altframe. Strange how i was the only one to notice... do you guys ALWAYS include atlframe? Smile | :)
 
/* Peace and love,
 *     Tweety
 */

GeneralRe: you misspelled something...memberSGarratt30 Apr '04 - 3:27 
oops! sorry about taht. Smile | :)
I'll fix it.
 
SGarratt
QuestionJust Show Scroll Bars?memberRick Pingry3 Apr '04 - 9:21 
I have a dialog box with a single static control in it. I would rather not use a dialog, but I have to go Modal on it since I am working from a seperate thread. Anyway, I would like to make it so that when the dialog was sized to smaller than the static control that the scroll bars would pop up like any scrollable window.
 
Please help Anyone Confused | :confused:
-- Rick
GeneralExcellentsussmcarolan15 Jan '04 - 20:21 
Nice work. I gave up on it. Now I can revisit sizable group boxes. Thanks!
 
markC
GeneralRe: ExcellentmemberSGarratt17 Jan '04 - 6:03 
Thanks.
 
I actually have redone this - with a lot of improvements, but I haven't got around to writing up the article update. I used WM_PRINT (to my memdc) as another poster suggested instead of doing raw GDI to paint the groupbox. WM_PRINT has the advantage of painting XP style groupboxes correctly, and using XP themes if they are active.
 
I also made some other improvments such as the ability to selectively add/delete controls from the deflicker list. MAybe im getting a little carried away with this Smile | :) .
 
anyway I will post the updated article next week, so look for it.
 
SGarratt
GeneralRe: ExcellentmemberDefenestration15 Apr '08 - 7:10 
Hi SGarratt,
 
Very useful article as I also dislike the flicker, so it's saved me some work. You mention you had an updated class with support for XP Themes, amongst other improvements.
 
Would it be possible to get hold of the updated class/article ?
 
Thanks in advance!
QuestionRelated to VS.NET bug?membered welch22 Dec '03 - 3:34 
I see something like this when I put a group box in a dialog in VS.NET: the background is not drawn at all. To fix this I have to set the transparent parameter. This problem does not happen in VC6. I suppose it is yet another bug in the resource editor in VS.NET.
GeneralSideeffects.memberTarmik11 Nov '03 - 23:07 

1. Memory DC uses additional memory (E.g. 100*100 pixels * 24 bit display =
100*100*3 = 30 Kb memory. multiply this by the number of groupboxes.)
 
2. During resize drawing bitmap (memory dc) is reallocated all over again - this causes delays to resize.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130523.1 | Last Updated 4 Nov 2003
Article Copyright 2003 by SGarratt
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid