使用内存DC绘图,然后实现双缓冲,避免绘图闪烁,这个小技术简单但很有效。但是仍然有很多人说使用了双缓冲,图片却仍然有闪烁,分析了几个这样的例子,发现

其实不是双缓冲的技术问题,而是使用者没有正确理解和使用双缓冲的方法。使用双缓冲要点如下:

1. 保证绘图过程中的所有CDC及其继承类指向内存DC。

在窗口或者视图中绘图,一般都是在OnDraw或者OnPaint事件中,但是有时根据需要绘图是通过调用其他类及函数完成比较复杂的绘制,在这些函数中,有时编写者会获取诸如CClientDC,然后绘图,此时的任何动作都会绕过缓冲区直接绘制到屏幕,从而造成闪烁。正确的做法是检查并修改所有绘图过程函数,避免直接获取CClientDC、CWindowDC、CPaintDC之类。而是采用传递CDC指针的方式写绘图类或者函数。

2. 修改OnEraseBkgnd(CDC* /*pDC*/)  事件

将代码屏蔽,改为一句    return TRUE;   这样做是避免使用原来父类代码中的擦除屏幕语句。

3. 另一个容易忽略的关键点-〉擦除背景。

第2条是必要的,避免了擦除背景的工作,但是这不代表背景不需要擦除了,只不过这个擦除过程要放到内存缓冲区中去做。

例如下面代码:

void CGraphView::EraseBkgnd(CDC* pDC)
{
 // TODO: Add your message handler code here and/or call default
   CRect rect;
   GetClientRect( &rect );
   CBrush brush;
   brush.CreateSolidBrush(GetColor(CColorClass::clrGraphBK) );
   pDC->FillRect( &rect, &brush );
 
}
 
void CGraphView::OnDraw(CDC* pDC)
{
  
 CRect rectClient;
 GetClientRect( &rectClient );
 CMemDC memDC(pDC, rectClient);
 EraseBkgnd(&memDC);            // OnEraseBkgnd 失效了,但是仍然需要在内存缓冲区中擦除背景
 m_graph.Redraw( &memDC, rectClient );
 
}

如果要求更高的绘图效率,重画时可以采用局部擦除的办法,即擦除一定区域内的代码。

使用双缓冲的整个步骤如下:

定义内存设备CMemDC,将所有绘图DC指向该设备  ---〉去掉擦除背景语句 ---〉在内存DC中擦除背景

-〉在内存DC中绘图 -〉结果切换到显示DC。

实际应用于复杂图形绘制,没有任何闪烁变化。

*文中提到的双缓冲代码CMemDC是个开源类,其内容如下:

#ifndef _MEMDC_H_
#define _MEMDC_H_
 
//////////////////////////////////////////////////
// CMemDC - memory DC
//
// Author: Keith Rule
// Email:  keithr@europa.com
// Copyright 1996-1999, 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
//
// This class implements a memory Device Context which allows
// flicker free drawing.
 
class CMemDC : public CDC {
protected:
   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.
     
   void Construct(CDC* pDC)
   {
        ASSERT(pDC != NULL);
 
        // Some initialization
        m_pDC = pDC;
        m_oldBitmap = NULL;
        m_bMemDC = !pDC->IsPrinting();
 
        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());
            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());
    }
 
// TRK begin
public:
   CMemDC(CDC* pDC                  ) : CDC() { pDC->GetClipBox(&m_rect); Construct(pDC); }
   CMemDC(CDC* pDC, const RECT& rect) : CDC() { m_rect = rect           ; Construct(pDC); }
// TRK end
     
   virtual ~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

原文链接:http://blog.csdn.net/r3000/article/details/5454262 

VC使用双缓冲避免绘图闪烁的正确使用方法【转】的更多相关文章

  1. VC使用双缓冲制作绘图控件

    最近用VC做了一个画图的控件.控件在使用的时候遇到点问题.在控件里画了图之后切换到其他页面,等再切换回来的时候,发现控件里画的图都不见了.这是因为VC里面,当缩小.遮挡页面后客户区域就会失效,当再次显 ...

  2. VC GDI双缓冲机制绘图防屏幕闪烁实现步骤

    在OnDraw(CDC* pDC) 中添加如下代码 CDC MemDC; //首先定义一个显示设备对象 CBitmap MemBitmap;//定义一个位图对象 //随后建立与屏幕显示兼容的内存显示设 ...

  3. VC++绘图时,利用双缓冲解决屏幕闪烁 转载

    最近做中国象棋,绘制界面时遇到些问题,绘图过程中屏幕闪烁,估计都会想到利用双缓冲来解决问题,但查了下网上双缓冲的资料,发现基本是MFC的,转化为VC++后,大概代码如下: void DrawBmp(H ...

  4. Java中用双缓冲技术消除闪烁

    在Java编写具有连贯变化的窗口程序时,通常的办法是在子类中覆盖父类的paint(Graphics)方法,在方法中使用GUI函数实现窗口重绘的过程.连贯变换的窗口会不断地调用update(Graphi ...

  5. HTML5_canvas_图片加载_双缓冲_跳帧闪烁问题

    canvas 图片加载 pen.drawImage(ele, showX, showY, imgWidth, imgHeight); ele    将 img 元素 加载到画布上 步骤 1. 创建一个 ...

  6. Android开发之用双缓冲技术绘图

    双缓冲技术主要用在画图,动画效果上,其原理就是:将资源先载入到缓冲区,然后再将缓冲区整个载入到View上面去. 双缓冲技术可以有效防止闪烁,提高显示质量. DrawView.java: package ...

  7. VC++中双缓冲技术画图

    用双缓冲,先在内存中绘制,然后拷贝到屏幕DC,这样就不会出现画出去的情况了,前段时间我也是为这个问题费了不少劲.我把我的一段代码给你看一下: CDC *pDC = m_drawbox.GetDC(); ...

  8. C# GDI+双缓冲技术

    我想有很多搞图形方面的朋友都会用到双缓冲技术的时候,而且有的时候她的确是个头疼的问题.最近我也要用双缓冲技术,程序怎么调试都不合适,当要对图形进行移动时,总是会出现闪烁抖动.在网上找了些资料,说得都不 ...

  9. Qt组件中的双缓冲无闪烁绘图

      双缓冲绘图在Qt4中,所有的窗口部件默认都使用双缓冲进行绘图.使用双缓冲,可以减轻绘制的闪烁感.在有些情况下,用户要关闭双缓冲,自己管理绘图.下面的语句设置了窗口部件的Qt::WA_PaintOn ...

随机推荐

  1. css reset 以及哪些元素有默认margin padding值

    很多网站在css reset 的时候有如下做法: body, ul, ol, li, p, h1, h2, h3, h4, h5, h6, form, label, dl, dt, dd,fields ...

  2. 使用PDO执行SQL语句exec()、query()

    在PHP脚本中,通过PDO执行SQL查询与数据库进行交互,可以分为三种不同的策略,使用哪一种方法取决于你要做什么操作. 1.使用PDO::exec()方法 当执行INSERT.UPDATE和DELET ...

  3. wifi 攻破

    链接1 wifi 加密方式 1,wep加密 2.WPA/WPA2-PSK加密 WPA2 的破解方式: 1 爆力破解 2,pin 破解 1) 先破解 pin 码 2)再用 minidwep-gtk 破解

  4. shell基础——变量定义

    快速参考: 变量定义格式: 变量名=值 str1="hello world" # define a string var str2=hello # define a string ...

  5. iOS 开发常用设置

    1. iOS设置app应用程序文件共享 设置流程 xcode 打开项目----在 info.plist 文件,添加 UIFileSharingEnabled 并设置属性为 YES, 在app内部,将您 ...

  6. linux命令学习(1)

    linux下的文件命名规则 1)除了/ 之外,所有的字符都合法. 2)有些字符最好不用,如空格符.制表符.退格符和字符@ # $ & ( ) - 等. 3)避免使用. 作为普通文件名的第一个字 ...

  7. C语言中一些非常酷的技巧(cool tricks)

    来自Quora,认为不错,就实践了一下. 1.  #if 0 ...... #endif 块中的内容不会被编译,由于凝视不同意嵌套,我们能够把临时不用的代码块放在 这里面. 2. 数组初始化的时候能够 ...

  8. 开源消息总线ActiveMQ

    一.消息中间件MOM(Message-Oriented Middleware) 消息中间件是解决异步分布式系统中通讯和排队问题的中间件技术.它利用高效可靠的消息传递机制进行平台无关的数据交流,并基于数 ...

  9. 10个Laravel4开发者必用扩展包

    Laravel是一个新的基于最新PHP版本号语法,支持IoC等设计模式的高速开发框架.眼下最新版本号为4.2,推荐安装PHP版本号5.5+. 本文列举10个基本软件包,都是开发人员使用Laravel框 ...

  10. 轻量级C语言实现的minixml解析库入门教程

    svn上的minixml源码下载.  svn co http://svn.msweet.org/mxml/tags/release-2.7/ 按照下载回来的源代码进行编译和安装.本教程只针对新手做一个 ...