使用内存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. Unknown system variable 'tx_read_only'

    SpringMVC+SpringDataJPA(1.4.2.RELEASE)+hibernate(4.2.7)+mysql6.0的开发环境,mysql-connector要older than5.1. ...

  2. Oracle EBS-SQL (MRP-1):检查期间内计划完成的任务.sql

    /*期间内车间任务下达记录数不包含配件任务*/ select     WE.DESCRIPTION                                                任务说 ...

  3. 鼠标拖放div 实现

    Javascript的mousemove事件类型是一个实时响应的事件,当鼠标指针的位置发生变化时(至少移动1个像素),就会触发mousemove事件.该事件响应的灵敏度主要参考鼠标指针移动速度的快慢, ...

  4. Codeforces 241B

    因为博客园的公式编辑有点坑,所以-- 原题

  5. CentOS安装与配置LNMP

    本文PDF文档下载:http://www.coderblog.cn/doc/Install_and_config_LNMP_under_CentOS.pdf 本文EPUB文档下载:http://www ...

  6. SDUT OJ 2783 小P寻宝记

    #include<iostream> #include<memory.h> #define N 10020 using namespace std; int dp[N],pi[ ...

  7. android开发之Animations的使用(二)

    android开发之Animations的使用(二) 本博文主要讲述的是android开发中的animation动画效果的使用,和上一篇博文不同的是,此次四种动画效果,主要使用的是xml文件实现的,提 ...

  8. 我的RTOS 之六 -- Touch移植(s5pv210+threadx+ucgui+touch)

    非常久没有关注RTOS了,所以也一直没有更新.近期闲了,把GPIO I2C调通了.简单移植了Touch.在S5PV210上使用. 调试I2C时.废了非常多周折,最后借助示波器才发现一个小小的错误.折腾 ...

  9. Ubuntu安装二:在VM中安装Ubuntu

    在VM中安装Ubuntu,先的安装VM,VM的安装请见:http://blog.csdn.net/u011043843/article/details/35291799 1.打开VM,新建虚拟机 2. ...

  10. Swift中编写单例的正确方式

    在之前的帖子里聊过状态管理有多痛苦,有时这是不可避免的.一个状态管理的例子大家都很熟悉,那就是单例.使用Swift时,有许多方法实现单例,这是个麻烦事,因为我们不知道哪个最合适.这里我们来回顾一下单例 ...