There are two articles dealing with this subject on this site, but
i guess sometimes it’s needed to free one single control from
flickering, and it’s not needed to use a complete new window-class. I
will show you a really small solution of the flickering-problem, which
uses the CMemDC-class from the article by Keith Rule. To make a
control flicker free you have to go three steps, as described now.
1. Override the OnEraseBkgnd()-routine of the control
Flickering apears, because the complete control is erased and it
needs some time to fill the control-area with some text/graphics or
whatever. There is a really short moment, when nothing can bee seen,
because the background was erased but nothing is written yet. That’s
why we don’t erase the background of the control anymore. to do this,
we have to override the OnEraseBkgnd()-routine of the control like
this:
BOOL CRecordList::OnEraseBkgnd(CDC* pDC) { return FALSE; }
2. Override the OnPaint()-routine of the control
The second thing to do, is to override the OnPaint()-routine. The
trick is, to paint the complete control into a memory device-context
and copy it in the original DC via BitBlt(). The CMemDC-class does
this work for you. Because we don’t erase the background anymore (see
above), we need to erase the memory-device-context with the
background-color of the control. A typical OnPaint() should look like
this:
void CRecordList::OnPaint() { CPaintDC dc(this); CMemDC memDC(&dc); CRect clip; memDC.GetClipBox(&clip); memDC.FillSolidRect(clip, GetSysColor(COLOR_WINDOW)); DefWindowProc(WM_PAINT, (WPARAM)memDC->m_hDC, (LPARAM)0); }
3. Override the EraseBkgnd()-routine of the control’s parent
Imagine the following situation. You have a dialog with the
flicker free control in it. And now the user resizes the window. What
happens? First of all, the background of the dialog is erased and
after that all controls of the window are redrawn. But when the
background is erased and THAN the controls are redrawn, we still have
flickering! That why we have to exclude the controls area out of the
clipping-box of the control’s parent. And here’s how we do it:
BOOL CListBar::OnEraseBkgnd(CDC *pDC) { CRect clip; m_Control->GetWindowRect(&clip); // get rect of the control ScreenToClient(&clip); pDC->ExcludeClipRect(&clip); pDC->GetClipBox(&clip); pDC->FillSolidRect(clip, GetSysColor(COLOR_BTNFACE)); return FALSE; }
That’s it. You can make near every control flicker free in this
way, but for some of the controls, you have to change the routines
above slightly. Like for the ListCtrl in Report-mode, because the
columne-header-area have to be excluded of the clip-box, like this:
void CRecordList::OnPaint() { CPaintDC dc(this); CRect headerRect; GetDlgItem(0)->GetWindowRect(&headerRect); ScreenToClient(&headerRect); dc.ExcludeClipRect(&headerRect); CMemDC memDC(&dc); . . . }