使用内存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. Apache-Tomcat 和 Apache-Maven配置

    1.1.下载安装文件 官网对应版本下载,例:apache-tomcat-8.0.35-windows-x64.zip 1.2.指定对应的安装目录: 例:D:\JavaSoft\apache-tomca ...

  2. 关于ThinkPHP下使用Uploadify插件 仅有火狐提示HTTP Error (302)错误的解决办法

    'VAR_SESSION_ID' => 'session_id', //修复uploadify插件无法传递session_id的bug 首先在项目目录中的Common/Conf/config.p ...

  3. Zabbix监控Linux主机设置

          说明: Zabbix监控服务端已经配置完成,现在要使用Zabbix对Linux主机进行监控. 具体操作: 以下操作在被监控的Linux主机进行,这里以CentOS 6.x系统为例. 一.配 ...

  4. EL表达式(转)

    转自:http://www.cnblogs.com/Fskjb/archive/2009/07/05/1517192.html EL 全名为Expression Language EL 语法很简单,它 ...

  5. Buffer Cache(缓冲区缓存)篇:keep缓冲区池(保留池)

    Buffer  Cache可以有三个池 默认缓冲区池 keep缓冲区池 recycling缓冲区池 --保留池和回收池可以独立于sga中的其他缓存分配内存.创建表的时候可以在storage子句中使用b ...

  6. #include <stdlib.h>

    1 _itoa 2 atoi 3 rand() 4 srand 1 _itoa _itoa(int value,char*string,int radix); int value 被转换的整数,cha ...

  7. SSH登陆服务器的简单命令

    SSh 用户名@目标Ip: 回车输入密码:

  8. 文件上传与下载/Mail

    文件上传与下载 提交方式:post 表单中要有文件上传的表单项 input type=”file”而且必须有name属性 表单类型要加入 encytype=”mulitpart/form-data” ...

  9. 不同版本的 IIS 中使用 ASP.NET MVC(C#)【转】

    由微软 ASP.NET 团队|2008 年 8 月 19 日 推特 在本教程中,您将学习在不同版本的 Internet Information Services 中如何使用 ASP.NET MVC 和 ...

  10. iSlider手机平台JS滑动组件

    iSlider手机平台JS滑动组件,无任何插件依赖.它能够处理任何元素,例如图片或者DOM元素.它有如下特性:能够自定义动画,自带的动画包括default, rotate, flip 和 depth你 ...