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
How to Draw a PNG format image on my form without flash???
Posted by Legacy on 02/12/2004 12:00amOriginally posted by: cfish
How to Draw a PNG format image on my form without flash???
ReplyCFormView with no special drawing
Posted by Legacy on 07/08/2003 12:00amOriginally posted by: Haim
Hi,
I've implemented the CMemDC in my derived CFormView class. I have no special drawing to do so in the OnDraw implementation I called CFormView::OnDraw(pDC).
The screen continue to flicker and the background become white (instead of gray).
What should I do if I have NO special drawing in my derived CFormView class?
ReplyHelp me about my flickering
Posted by Legacy on 11/06/2002 12:00amOriginally posted by: Adriano
I have serious problems with flickering in my Dialog based application. Simply I must draw (every 100 ms about) some rectangles, so I wrote the code to paint these rectangles in the OnPaint method (member of my sub-class Cdialog type). How I can resolve my problem?
Thank you very much.
Adriano
ReplyThis code Rocks!!! Great job to the code writer.
Posted by Legacy on 10/23/2002 12:00amOriginally posted by: Joe
This code works very well.
ReplyMemory leaks using pWnd->GetDC();
Posted by Legacy on 04/15/2002 12:00amOriginally posted by: Ooms Gauthier
When you pass a DC using pCDC = pWnd->GetDC(); to the CMemDC constructor there will be a memory leak, because the pCDC wont be released (pWnd->ReleaseDC(pCMemDC); wont release the pCDC). So what i've done to fix this is the following:
CClientDC pCCDC(pWnd);
CDC* pCDC = &pCCDC
and then passing this pCDC with the CMemDC constructor. CClientDC gets released automatically.
Hope that helps some people, took me a while to find this one.
Reply
Don't Redraw all bitmaps when resize the window
Posted by Legacy on 10/10/2001 12:00amOriginally posted by: vilas
ReplyHow about CPaintDC?
Posted by Legacy on 04/28/2001 12:00amOriginally posted by: _sailinsky
If i wanna pass a CPaintDC variable to the construtor of the CMemDC,there'll incur a problem in the line pDC->GetClipBox.If you use CMemDC in your CYourClass::OnPaint,in this function a CPaintDC variable is constructed,which is generated by MFC Appwizard.You know after call of the constructor,there is no any clip box.So that line of code will get a NULL rectangle.As a result the subsequent code will also work improperly.
Replyflicker free redrawing
Posted by Legacy on 10/13/2000 12:00amOriginally posted by: calum
i read with interest about reducing the flicker on resizing and dragging - which has been bugging me in my app. but what really bugs me is that i get flicker as the app updates the contents of my grid control. i populate a grid control (msflexgrid) with data from a list of objects (all the same kind). when i get an update to an object, i call updateallviews to get the ondraw function to loop through the list of objects and update the values in the grid. but i think the actual grid itself is being redrawn each time, and not the individual cells. i wouldn;t mind about the flickering during resizing, as i don;t resize it much, but with lots of entries in the grid needing to be changed every couple of seconds, it's going to give me epilepsy or something.
can you help? i suspect it;s the way i use updateallviews to cause the view to update itself.
thanks
calum
ReplyHow to implement FASTER code ??
Posted by Legacy on 09/03/2000 12:00amOriginally posted by: Kyle Katarn
hi there,
Brad Larsen wrote some code to make the CMemDC class faster.
He also wrote, that he creates the bitmap outside the OnDraw function, so it's not created at every draw.
My problem is to create the bitmap outside.
Example:
void CMyView::OnDraw(CDC* pDC)
{
CDC memDC;
CRect rDisplay;
CBitmap bmpBuf;
CNFODoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
GetClientRect(&rDisplay);
memDC.CreateCompatibleDC(pDC);
bmpBuf.CreateCompatibleBitmap(pDC,rDisplay.Width(), risplay.Height()); //here's the problem. The function needs pDC as first parameter, but how can I get acces to it @ Initialize() ??
CBitmap *pOldBitmap = memDC.SelectObject(&bmpBuf);
Thanx in advance
Kyle K.
ReplyHow to get filter free in dialog
Posted by Legacy on 05/07/2000 12:00amOriginally posted by: winwolf
How can I get filter free in dialog? I thik it is different with CView, right? and I can not find OnDraw().
ReplyLoading, Please Wait ...