Click here to Skip to main content
5,790,650 members and growing! (20,910 online)
Email Password   helpLost your password?
Desktop Development » Button Controls » Non-rectangular Buttons     Intermediate

Flicker free resizable custom control

By JanKotowski

This dynamically reziable control does not flicker. The article describes the problem and the technique used to solve the flickering.
VC7, C++Windows, Win2K, WinXP, MFC, GDI, GDI+, VS.NET2002, Visual Studio, Dev

Posted: 9 Feb 2005
Updated: 31 Oct 2005
Views: 55,005
Bookmarked: 56 times
Announcements
Loading...



Search    
Advanced Search
Sitemap
13 votes for this Article.
Popularity: 4.98 Rating: 4.47 out of 5
0 votes, 0.0%
1
2 votes, 15.4%
2
1 vote, 7.7%
3
1 vote, 7.7%
4
9 votes, 69.2%
5

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



Occupation: Web Developer
Location: Canada Canada

Other popular Button Controls articles:

Article Top
Sign Up to vote for this article
You must Sign In to use this message board.
FAQ FAQ Noise ToleranceSearch Search Messages 
 Layout  Per page   
 Msgs 1 to 3 of 3 (Total in Forum: 3) (Refresh)FirstPrevNext
GeneralDoing the same thing slightly differently...memberJun Du16:44 31 Oct '05  
GeneralWS_CLIPCHILDRENmemberbeerboy_2223:46 9 Feb '05  
GeneralRe: WS_CLIPCHILDRENmemberJanKotowski15:40 10 Feb '05  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 31 Oct 2005
Editor: Smitha Vijayan
Copyright 2005 by JanKotowski
Everything else Copyright © CodeProject, 1999-2009
Web08 | Advertise on the Code Project