|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionI 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. BackgroundMany articles on the subject suggest to:
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 codeThe 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 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 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 Double Buffering: Since all drawing is done in GDI+, I used a 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 Finally, make sure that the control itself has Points of InterestDownload the demo and drag it by the corner. See the button change shape without any flicker.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||