Home

GDI Topics: Flicker-Free Drawing

 
 

Introduction

If you display a picture or draw a shape in a device context using CDC, when the view is resized, there a nasty effect of a double drawing that shows some gray or white sections over the actual drawing area. This is referred to as flicker.

Practical Learning Practical Learning: Producing Flickering 

 

  1. To produce the flicker effect, create an MFC Application named FlickerFree
  2. Create it as a Single Document type
  3. Using the Resource Symbols dialog box, create an ID named IDT_OCCUR
  4. In the view header file, declare the following variables:
     
    // FlickerFreeView.h : interface of the CFlickerFreeView class
    //
    
    
    #pragma once
    
    
    class CFlickerFreeView : public CView
    {
    protected: // create from serialization only
    	CFlickerFreeView();
    	DECLARE_DYNCREATE(CFlickerFreeView)
    
    // Attributes
    public:
    	CFlickerFreeDoc* GetDocument() const;
    
    // Operations
    public:
    
    // Overrides
    public:
    	virtual void OnDraw(CDC* pDC);  // overridden to draw this view
    	virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
    protected:
    	virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
    	virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
    	virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);
    
    // Implementation
    public:
    	virtual ~CFlickerFreeView();
    #ifdef _DEBUG
    	virtual void AssertValid() const;
    	virtual void Dump(CDumpContext& dc) const;
    #endif
    
    protected:
    
    // Generated message map functions
    protected:
    	DECLARE_MESSAGE_MAP()
    	
    private:
    	int x;
    	int y;
    	int w;
    	int h;
    	BOOL MovingRight;
    };
    
    #ifndef _DEBUG  // debug version in FlickerFreeView.cpp
    inline CFlickerFreeDoc* CFlickerFreeView::GetDocument() const
       { return reinterpret_cast<CFlickerFreeDoc*>(m_pDocument); }
    #endif
  5. In the constructor of the view class, initialize the variables as follows:
     
    CFlickerFreeView::CFlickerFreeView()
    {
    	// TODO: add construction code here
    	x = 0;
    	y = 100;
    	w = 100;
    	h = 150;
    	MovingRight = TRUE;
    }
  6. Generate the OnInitialUpdate event for the view class and use it to initialize the timer as follows:
     
    void CFlickerFreeView::OnInitialUpdate()
    {
    	CView::OnInitialUpdate();
    
    	// TODO: Add your specialized code here and/or call the base class
    	SetTimer(IDT_OCCUR, 10, NULL);
    }
  7. Change the OnDraw event as follows:
     
    void CFlickerFreeView::OnDraw(CDC* pDC)
    {
    	CFlickerFreeDoc* pDoc = GetDocument();
    	ASSERT_VALID(pDoc);
    	if (!pDoc)
    		return;
    
    	// TODO: add draw code for native data here
    	CRect rect;
    	CBrush brsBlack, *brsOld;
    
    	GetClientRect(&rect);
    	brsBlack.CreateSolidBrush(RGB(0, 0, 0));
    
    	brsOld = pDC->SelectObject(&brsBlack);
    	pDC->Rectangle(rect.left, rect.top, rect.Width(), rect.Height());
    
    	CPen   penRed, *penOld;
    	penRed.CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
    	penOld = pDC->SelectObject(&penRed);
    
    	pDC->Rectangle(x, y, x + 100, h);
    
    	pDC->SelectObject(penOld);
    	pDC->SelectObject(brsOld);
    }
  8. Generate the event of the WM_TIMER message for the view class and implement it as follows:
     
    void CFlickerFreeView::OnTimer(UINT_PTR nIDEvent)
    {
    	// TODO: Add your message handler code here and/or call default
    	CRect rect;
    	GetClientRect(&rect);
    
    	if( x < 0 )
    	{
    		x = 0;
    		MovingRight = TRUE;
    	}
    	if( x > (rect.Width() - 100) )
    	{
    		x = rect.Width() - 100;
    		MovingRight = FALSE;
    	}
    
    	Invalidate();
    
    	if( MovingRight == TRUE )
    		x++;
    	else
    		x--;
    
    	CView::OnTimer(nIDEvent);
    }
  9. Execute the application to see the result and notice the flickering effect
  10. Close the application

Flicker Free

Fortunately, in most cases, getting rid of, or reducing, the flickering effect can be easy. To take care of it, override the OnEraseBkgnd event and simply return TRUE from it.

Practical Learning Practical Learning: Taking Care of Flickering 

  1. Generate the event of the WM_ERASEBKGND message of the view class and change its return value as follows:
     
    BOOL CFlickerFreeView::OnEraseBkgnd(CDC* pDC)
    {
    	// TODO: Add your message handler code here and/or call default
    
    	return TRUE;// CView::OnEraseBkgnd(pDC);
    }
  2. Execute the application again to see the result
 

Home Copyright © 2006 FunctionX, Inc.