Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

CDialogResize based class with no groupbox flicker

0.00/5 (No votes)
3 Nov 2003 2  
Get rid of annoying groupbox flicker when using resizeable windows; also effects adjustable minimum and maximum window size.

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