解决MFC闪烁的CMemDC类

来源:互联网 发布:linux 关闭snmp 编辑:程序博客网 时间:2024/05/29 18:31

翻译来源:解决MFC闪烁的CMemDC类

https://www.codeproject.com/Articles/33/Flicker-Free-Drawing-In-MFC

我在网上看到几篇很好的文章 CmemDC类 的使用方法利用CMemDC画图的两种方法,然后找到了CMemDC类的来源算是对CMemDC类资源的补充。

从VS2008开始提供了CMemDC Class

这里主要介绍第三方CMemDC类的封装,还能随时得到最新的CMemDC类,源代码请自行到codeproject网站下载。已搬运至CSDN。

  • Download demo project - 172 Kb
  • Download demo ActiveX control - 28 Kb

Sample Image

一个简单的动画示例用于显示CMemDC几种模式

一、介绍

从MFC应用程序中删除闪烁是一个值得深入讨论领域。您可以在书籍和在线查找主题。然而,所提出的技术有些复杂,通常难以添加到现有的应用程序中。一种经常提出的技术称为双缓冲。双缓冲允许在屏幕外存储器中绘制新屏幕,然后将完成的屏幕置于物理屏幕上。

本文介绍了一个类CMemDC,它将与写入相关的大多数问题封装到离屏缓冲区。添加CMemDC到现有应用程序或MFC Active X控件几乎是微不足道的。

二、修改MFC应用程序使用CMemDC

  • 在你的项目中添加文件memdc.h。
  • 将#include“memdc.h”行添加到stdafx.h。
  • 添加一个Windows消息处理程序WM_ERASEBKGND
  • 更改消息处理程序中的代码如下:
    // Change this codeBOOL CExampleView::OnEraseBkgnd(CDC* pDC) {      // TODO: Add your message handler code here and/or call default      return CView::OnEraseBkgnd(pDC);} // To this codeBOOL CExampleView::OnEraseBkgnd(CDC* pDC) {      return FALSE;}
  • 将您的OnDraw 代码更改为以下内容:
    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}

在进行这些更改后,编译代码,并注意到您之前看到的闪烁已经消失了。

三、修改MFC Active X控件以使用CMemDC

要添加CMemDC 支持,请按照向应用程序添加支持的说明进行操作,但是您可以对该OnDraw 功能进行一些小的更改

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 }

唯一实质的区别是将rcBounds传递给CMemDC构造函数。

四、源代码

#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