Flicker free drawing using memory DC
Posted
by Keith Rule
on March 23rd, 1999
Download a sample file. The zip file is 17KB.
Flicker Free Updates Using CMemDC
Creating an MS-Windows application is often an absorbing task. Many issues are often postponed until near the end of development. One commonly postponed issue is removing flicker from screen redraws. This short tip explains how to do this using the CMemDC class with MFC. This class isn't a part of MFC, but after you've seen how useful it is you may add it to your MFC toolbox.Exacerbating the Problem
One of the best ways to exacerbate flickering is to enable the "Show windows contents while dragging" mode found in the Plus! Tab of the Display properties in Windows 95. This mode causes your application to be redrawn while it is resized.
A Simple Solution
The reason your application is flickering is that the original image is being erased and then redrawn in quick succession when the application is resized. A common technique to reduce or eliminate this problem is to not erase the image, but rather, to draw to an off screen buffer and BitBliting the buffer to the screen. This eliminates the flashing caused by erasing, and the flashing cause by being able to see individual drawing operations on the screen. To disable erasing you need to intercept the WM_ERASEBKGND message and return FALSE.BOOL CNoFlickerView::OnEraseBkgnd(CDC* pDC)
{
return FALSE;
}
To draw to an off screen buffer you need to create a memory CDC, draw to it, and BitBlit the result to the screen. You can do this by using the CMemDC class. This class is very small, just a few lines, but it makes handles most of the off screen drawing issues.
#ifndef _MEMDC_H_
#define _MEMDC_H_
//////////////////////////////////////////////////
// CMemDC - memory DC
//
// Author: Keith Rule
// Email: keithr@europa.com
// Copyright 1996-1997, Keith Rule
//
// You may freely use or modify this code provided this
// Copyright is included in all derived versions.
//
// History - 10/3/97 Fixed scrolling bug.
// Added print support.
//
// This class implements a memory Device Context
class CMemDC : public CDC {
private:
CBitmap m_bitmap; // Offscreen bitmap
CBitmap* m_oldBitmap; // bitmap originally found in CMemDC
CDC* m_pDC; // Saves CDC passed in constructor
CRect m_rect; // Rectangle of drawing area.
BOOL m_bMemDC; // TRUE if CDC really is a Memory DC.
public:
CMemDC(CDC* pDC) : CDC(), m_oldBitmap(NULL), m_pDC(pDC)
{
ASSERT(m_pDC != NULL); // If you asserted here, you passed in a NULL CDC.
m_bMemDC = !pDC->IsPrinting();
if (m_bMemDC){
// Create a Memory DC
CreateCompatibleDC(pDC);
pDC->GetClipBox(&m_rect);
m_bitmap.CreateCompatibleBitmap(pDC, m_rect.Width(), m_rect.Height());
m_oldBitmap = SelectObject(&m_bitmap);
SetWindowOrg(m_rect.left, m_rect.top);
} else {
// Make a copy of the relevent parts of the current DC for printing
m_bPrinting = pDC->m_bPrinting;
m_hDC = pDC->m_hDC;
m_hAttribDC = pDC->m_hAttribDC;
}
}
~CMemDC()
{
if (m_bMemDC) {
// Copy the offscreen bitmap onto the screen.
m_pDC->BitBlt(m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(),
this, m_rect.left, m_rect.top, SRCCOPY);
//Swap back the original bitmap.
SelectObject(m_oldBitmap);
} else {
// All we need to do is replace the DC with an illegal value,
// this keeps us from accidently deleting the handles associated with
// the CDC that was passed to the constructor.
m_hDC = m_hAttribDC = NULL;
}
}
// Allow usage as a pointer
CMemDC* operator->() {return this;}
// Allow usage as a pointer
operator CMemDC*() {return this;}
};
#endif
To draw off screen and blit the result onto the screen you simply change the argument name from pDC to dc, and add a CMemDC local variable named pDC.
void CNoFlickerView::OnDraw(CDC* dc)
{
CRect rcBounds;
GetClientRect(&rcBounds);
CMemDC pDC(dc, rcBounds);
pDC->FillRect(rcBounds, CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));
pDC->Ellipse(rcBounds);
}
This updated version of the OnDraw() function in conjunction with overriding the OnEraseBkgnd() function will eliminate the flicker in your application.

Comments
There are no comments yet. Be the first to comment!