
A simple animation example which is used to show CMemDC in several mode
Introduction
Removing flicker from an MFC application is well-covered territory. You can find the topic addressed in books, and on-line. However, the techniques presented are somewhat complicated and are usually difficult to add to an existing application. One often-presented technique is called double buffering. Double buffering allows the new screen to be drawn in off-screen memory, and then the completed screen is bit-blited back onto the physical screen.
This article presents a class called CMemDC that encapsulates most of the issues associated with writing to off-screen buffers. Adding CMemDC to an existing application or MFC Active X control is nearly trivial.
Modifying an MFC Application to use CMemDC
Compile your code after you've made these changes and you will notice that the flicker you had seen before is gone.
Modifying a MFC Active X Control to use CMemDC
To add CMemDC support you follow the instruction for adding the support to an application, however you make one small change in the OnDraw function.
void CParticleTestCtlCtrl::OnDraw(CDC* pdc, const CRect& rcBounds,
const CRect& rcInvalid)
{
CMemDC pDC(pdc, &rcBounds);
}
The only substantial difference is that the rcBounds is passed to the CMemDC constructor.
Source Code
#ifndef _MEMDC_H_
#define _MEMDC_H_
class CMemDC : public CDC {
private:
CBitmap m_bitmap; CBitmap* m_oldBitmap; CDC* m_pDC; CRect m_rect; BOOL m_bMemDC; public:
CMemDC(CDC* pDC, const CRect* pRect = NULL) : CDC()
{
ASSERT(pDC != NULL);
m_pDC = pDC;
m_oldBitmap = NULL;
m_bMemDC = !pDC->IsPrinting();
if (pRect == NULL) {
pDC->GetClipBox(&m_rect);
} else {
m_rect = *pRect;
}
if (m_bMemDC) {
CreateCompatibleDC(pDC);
pDC->LPtoDP(&m_rect);
m_bitmap.CreateCompatibleBitmap(pDC, m_rect.Width(),
m_rect.Height());
m_oldBitmap = SelectObject(&m_bitmap);
SetMapMode(pDC->GetMapMode());
SetWindowExt(pDC->GetWindowExt());
SetViewportExt(pDC->GetViewportExt());
pDC->DPtoLP(&m_rect);
SetWindowOrg(m_rect.left, m_rect.top);
} else {
m_bPrinting = pDC->m_bPrinting;
m_hDC = pDC->m_hDC;
m_hAttribDC = pDC->m_hAttribDC;
}
FillSolidRect(m_rect, pDC->GetBkColor());
}
~CMemDC()
{
if (m_bMemDC) {
m_pDC->BitBlt(m_rect.left, m_rect.top,
m_rect.Width(), m_rect.Height(),
this, m_rect.left, m_rect.top, SRCCOPY);
SelectObject(m_oldBitmap);
} else {
m_hDC = m_hAttribDC = NULL;
}
}
CMemDC* operator->()
{
return this;
}
operator CMemDC*()
{
return this;
}
};
#endif
I work at Tektronix in Beaverton OR. I've been programming for fun since 1975 (I started while in a Computer Explorer Scout group in Spokane WA). I've been programming in C since 1979 and I've been working professionally since 1983.
I really enjoy www.codeproject.com. It has saved me an incredible amount of time. I only hope my small contributions have given back some of what I've taken.