Flicker free drawing using memory DC

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

Windows NT also has a similar mode that may be set. If you enable this mode and your application flashes or flicker when resized this tip will probably help.

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.

Caveats and Such

If you haven't guessed, this solution isn't a cure all. If your application is slow to draw it will still be slow when using this technique. However, for many situations, this simple class and technique will reduce or eliminate flickering with just a couple of minutes if implementation code.



Comments

  • How to Draw a PNG format image on my form without flash???

    Posted by Legacy on 02/12/2004 12:00am

    Originally posted by: cfish

    How to Draw a PNG format image on my form without flash???

    Reply
  • CFormView with no special drawing

    Posted by Legacy on 07/08/2003 12:00am

    Originally 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?

    Reply
  • Help me about my flickering

    Posted by Legacy on 11/06/2002 12:00am

    Originally 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

    Reply
  • This code Rocks!!! Great job to the code writer.

    Posted by Legacy on 10/23/2002 12:00am

    Originally posted by: Joe

    This code works very well.

    Reply
  • Memory leaks using pWnd->GetDC();

    Posted by Legacy on 04/15/2002 12:00am

    Originally 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:00am

    Originally posted by: vilas

    My question is
    
    suppose i have 5 to 6 bitmap on the view when i resize the window
    i dont want to redraw all the bitmaps.
    is there any method for this

    Reply
  • How about CPaintDC?

    Posted by Legacy on 04/28/2001 12:00am

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

    Reply
  • flicker free redrawing

    Posted by Legacy on 10/13/2000 12:00am

    Originally 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

    Reply
  • How to implement FASTER code ??

    Posted by Legacy on 09/03/2000 12:00am

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

    Reply
  • How to get filter free in dialog

    Posted by Legacy on 05/07/2000 12:00am

    Originally 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().

    Reply
  • Loading, Please Wait ...

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: August 20, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT When you look at natural user interfaces as a developer, it isn't just fun and games. There are some very serious, real-world usage models of how things can help make the world a better place – things like Intel® RealSense™ technology. Check out this upcoming eSeminar and join the panel of experts, both from inside and outside of Intel, as they discuss how natural user interfaces will likely be getting adopted in a wide variety …

  • Event Date: April 15, 2014 The ability to effectively set sales goals, assign quotas and territories, bring new people on board and quickly make adjustments to the sales force is often crucial to success--and to the field experience! But for sales operations leaders, managing the administrative processes, systems, data and various departments to get it all right can often be difficult, inefficient and manually intensive. Register for this webinar and learn how you can: Align sales goals, quotas and …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds