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

Flicker free resizable custom control

By , 31 Oct 2005
Rate this:
Please Sign up or sign in to vote.

Sample Image

Introduction

I had read every article on flicker-free drawing, yet I could not make it work for my resizable custom control. There are a couple of known issues, but there is also a rarely mentioned subtlety involved. In this article, I will discuss all the issues involved and how to approach them.

The sample included in this article is an implementation of an elliptical button control. The drawing is done using GDI+. The round button changes outer color as the mouse cursor rolls over. The inner color changes as the mouse is clicked on the button. The control stretches and shrinks as the dialog box is dragged.

Background

Many articles on the subject suggest to:

  1. use double buffering
  2. override OnEraseBkgnd and return TRUE.

Well, I implemented both and it still flickered. The problem most visibly occurred during resizing, when the whole dialog was repainted. The issue was that the dialog box would erase my custom control as it erased its own background. Therefore, every time I resized the dialog, I would get a flicker due to the dialog box painting grey over my control before the control repainted itself.

Using the code

The clipping solution: tell the dialog to erase everything but the region occupied by the round control. The easiest way to accomplish this is to set the Windows style to WS_CLIPCHILDREN. You can do this programmatically in "OnInitDialog" method (or you can set this dialog property in Visual Studio's design view):

BOOL CNoFlickerDlg::OnInitDialog()
{
    ....

    // Tell the dialog NOT to erase children controls
    ModifyStyle(0, WS_CLIPCHILDREN);

    return TRUE;
    // return TRUE  unless you set the focus to a control
}

Since my control has a custom (round) region, it must be re-computed each time the control changes shape or size. In order for this to work correctly, the best place to call the ReCalculateDimensions function is from the dialog's OnEraseBkgnd, like so:

BOOL CNoFlickerDlg::OnEraseBkgnd(CDC* pDC)
{
    m_cButtonControl.ReCalculateDimensions();

    return CDialog::OnEraseBkgnd(pDC);
}

The reason you have to make the call here is important. The dialog will exclude the control region from its surface (that is being erased) based on what the control region is set to be. Therefore, by calling it right before CDialog::OnEraseBkgnd, you ensure that the control region is up to date right before it is clipped.

Double Buffering: Since all drawing is done in GDI+, I used a CachedBitmap class to help me with double buffering. The code comes down to the following few lines:

void CButtonControl::OnPaint()
{
    // device context for painting
    CPaintDC dc(this);

    Graphics graphics(dc.m_hDC);

    // Only redraw the control if the buffer is dirty
    if (m_bDirtyBuffer)
    {
        DrawButton(graphics);
        m_bDirtyBuffer = FALSE;
    }

    graphics.DrawCachedBitmap(m_pCachedBitmap, 0, 0);
}

As you can tell from the code above, the actual drawing is only done when m_bDirtyBuffer flag is set to true. Every other time, the painting is done using a cached bitmap. You set the flag to true whenever the control is resized (i.e., in OnSize method).

Finally, make sure that the control itself has OnEraseBkgnd method overridden and returns TRUE. This will make your controls flicker free!

Points of Interest

Download the demo and drag it by the corner. See the button change shape without any flicker.

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

JanKotowski
Web Developer
Canada Canada
No Biography provided

Comments and Discussions

 
GeneralDoing the same thing slightly differently... PinmemberJun Du31-Oct-05 15:44 
GeneralWS_CLIPCHILDREN Pinmemberbeerboy_229-Feb-05 22:46 
GeneralRe: WS_CLIPCHILDREN PinmemberJanKotowski10-Feb-05 14:40 

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

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140415.2 | Last Updated 31 Oct 2005
Article Copyright 2005 by JanKotowski
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid