Click here to Skip to main content
6,596,602 members and growing! (18,714 online)
Email Password   helpLost your password?
Multimedia » GDI » Device Contexts     Intermediate

Flicker Free Drawing In MFC

By Keith Rule

A simple animation example which is used to show CMemDC in several modes
VC6, Windows, MFC, GDI, Dev
Posted:20 Nov 1999
Updated:25 Mar 2002
Views:428,566
Bookmarked:219 times
Announcements
Loading...
 
Search    
Advanced Search
Add to IE Search
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
207 votes for this article.
Popularity: 11.23 Rating: 4.85 out of 5
2 votes, 1.5%
1

2
3 votes, 2.2%
3
5 votes, 3.7%
4
124 votes, 92.5%
5

Sample Image
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

  • Add the file memdc.h in your project.
  • Add the line #include "memdc.h" to stdafx.h.
  • Add a windows message handler for WM_ERASEBKGND.
  • Change the code in the message handler as follows:
    // Change this code
    
    BOOL CExampleView::OnEraseBkgnd(CDC* pDC) 
    {
          // TODO: Add your message handler code here and/or call default
    
          return CView::OnEraseBkgnd(pDC);
    }
     
    // To this code
    
    BOOL CExampleView::OnEraseBkgnd(CDC* pDC) 
    {
          return FALSE;
    }
  • Change your OnDraw code to the following:
    void CExampleView::OnDraw(CDC* dc)
    {
        CMemDC pDC(dc);
        CExampleDoc* pDoc = GetDocument();
        ASSERT_VALID(pDoc);
        // TODO: add draw code for native data here - use pDC 
    
         //as the device context to draw to
    
    }

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);
    // TODO: add draw code for native data here

    // - use pDC as the device context to draw 

}

The only substantial difference is that the rcBounds is passed to the CMemDC constructor.

Source Code

#ifndef _MEMDC_H_
#define _MEMDC_H_
 
//////////////////////////////////////////////////

// CMemDC - memory DC

//

// Author: Keith Rule

// Email:  keithr@europa.com

// Copyright 1996-2002, 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. - KR

//

//       11/3/99 Fixed most common complaint. Added

//            background color fill. - KR

//

//       11/3/99 Added support for mapping modes other than

//            MM_TEXT as suggested by Lee Sang Hun. - KR

//

//       02/11/02 Added support for CScrollView as supplied

//             by Gary Kirkham. - KR

//

// This class implements a memory Device Context which allows

// flicker free drawing.

 
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, const CRect* pRect = NULL) : CDC()
    {
        ASSERT(pDC != NULL); 
 
        // Some initialization

        m_pDC = pDC;
        m_oldBitmap = NULL;
        m_bMemDC = !pDC->IsPrinting();
 
        // Get the rectangle to draw

        if (pRect == NULL) {
             pDC->GetClipBox(&m_rect);
        } else {
             m_rect = *pRect;
        }
 
        if (m_bMemDC) {
             // Create a Memory DC

             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 {
             // 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;
        }
 
        // Fill background 

        FillSolidRect(m_rect, pDC->GetBkColor());
    }
    
    ~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 accidentally 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

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Keith Rule


Member
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.

Occupation: Web Developer
Location: United States United States

Other popular GDI articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 25 of 203 (Total in Forum: 203) (Refresh)FirstPrevNext
GeneralSetProcessDefaultLayOut LAYOUT_RTL PinmemberFarid Z19:36 27 Oct '09  
NewsMFC Feature Pack for Visual C++ 2008 Pinmembermykel8:54 20 Oct '09  
GeneralRe: MFC Feature Pack for Visual C++ 2008 PinmemberKeith Rule11:01 20 Oct '09  
GeneralRe: MFC Feature Pack for Visual C++ 2008 Pinmembermykel1:22 21 Oct '09  
GeneralThanks Pinmemberxsm_12622:48 12 Jun '09  
Answer... PinmemberMember 426330221:06 22 Feb '09  
QuestionCDialog Based application with memdc.h and MSFlexgrid Control Pinmembertmg512814:03 17 Feb '09  
GeneralThanks~!! PinmemberMember 377536115:09 12 Feb '09  
GeneralVery good job !!! Pinmemberraymondnana4:24 29 Jan '09  
Generalcool... Pinmemberauralius19:11 21 Dec '08  
GeneralCMemDC & Dialog Menu PinmemberSteven Pence10:38 8 Dec '08  
GeneralHow to use in Controls? Pinmemberblamond12:14 30 Apr '08  
GeneralRe: How to use in Controls? Pinmemberblamond9:52 6 May '08  
Generalchild windows Pinmembertoddma11:16 9 Nov '07  
GeneralThanks for some greate time / pain saving! PinmemberSoftwareGeek1:08 8 Nov '07  
GeneralNice work, but... PinmemberSimpleProgrammer6:51 15 Aug '07  
GeneralRe: Nice work, but... Pinmemberbrian.lee21:47 5 Sep '07  
GeneralNot recognising CDC members Pinmemberfacelaunch7:53 3 Aug '07  
QuestionStill flickering Pinmemberfacelaunch10:13 3 Aug '07  
AnswerRe: Still flickering Pinmemberfacelaunch10:55 3 Aug '07  
GeneralRe: Not recognising CDC members PinmemberGuptaP9:25 16 Aug '07  
GeneralRe: Not recognising CDC members PinmemberJDENISW9:55 14 Jun '09  
QuestionDisplay non-solid-color background in scroll-view correctly Pinmemberchen_zd3:45 11 Jun '07  
GeneralThank u. PinmemberMurali_mom22:16 30 May '07  
GeneralHowto use SetViewportExt with CMemDC PinmemberPospiech4:17 13 May '07  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 25 Mar 2002
Editor: Chris Maunder
Copyright 1999 by Keith Rule
Everything else Copyright © CodeProject, 1999-2009
Web21 | Advertise on the Code Project