转自 MFC绘图不闪烁——双缓冲技术[转]

  在VC/MFC用CDC绘图时,频繁的刷新,屏幕会出现闪烁的现象,CPU时间占用率相当高,绘图效率极低,很容易出现程序崩溃

  所谓双缓冲技术,下面是百度百科的解释:

  我们看电视时,看到的屏幕称为OSD层,也就是说,只有在OSD层上显示图像我们才能看到。现在,我需要创建一个虚拟的、看不见但是可以在上面画图(比如说画点、线)的OSD层,我称之为offscreen(后台缓冲区)。这个offscreen存在于内存中,我们在上面画图,这个offscreen上面的东西可以显示在OSD层上,需要一个创建这个offscreen的函数,返回这个offscreen的句柄(整型指针)宽度、高度、指向新建offscreen数据缓冲区的指针,该缓冲区是一个在函数外创建的offscreen的数据缓冲区,大小是offscreen的高度*宽度*每个像素点数据的大小。

  闪烁是图形编程的一个常见问题。需要多重复杂绘制操作的图形操作会导致呈现的图像闪烁或具有其他不可接受的外观。双缓冲的使用解决这些问题。双缓冲使用内存缓冲区来解决由多重绘制操作造成的闪烁问题。当启用双缓冲时,所有绘制操作首先呈现到内存缓冲区,而不是屏幕上的绘图图面所有绘制操作完成后,内存缓冲区直接复制到与其关联的绘图图面。因为在屏幕上只执行一个图形操作,所以消除了由复杂绘制操作造成的图像闪烁。

    在图形图象处理编程过程中,双缓冲是一种基本的技术。我们知道,如果窗体在响应WM_PAINT消息的时候要进行复杂的图形处理,那么窗体在重绘时由于过频的刷新而引起闪烁现象。解决这一问题的有效方法就是双缓冲技术。因为窗体在刷新时,总要有一个擦除原来图象的过程OnEraseBkgnd,它利用背景色填充窗体绘图区,然后在调用新的绘图代码进行重绘,这样一擦一写造成了图象颜色的反差。当WM_PAINT的响应很频繁的时候,这种反差也就越发明显。于是我们就看到了闪烁现象。

  我们会很自然的想到,避免背景色的填充是最直接的办法。但是那样的话,窗体上会变的一团糟。因为每次绘制图象的时候都没有将原来的图象清除,造成了图象的残留,于是窗体重绘时,画面往往会变的乱七八糟。所以单纯的禁止背景重绘是不够的。我们还要进行重新绘图,但要求速度很快,于是我们想到了使用BitBlt函数。它可以支持图形块的复制,速度很快。我们可以先在内存中作图,然后用此函数将做好的图复制到前台,同时禁止背景刷新,这样就消除了闪烁。以上也就是双缓冲绘图的基本的思路。

  先按普通做图的方法进行编程。即在视类的OnDraw函数中添加绘图代码。在此我们绘制若干同心圆,代码如下:

CBCDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
CPoint ptCenter;
CRect rect,ellipseRect;
GetClientRect(&rect);
ptCenter = rect.CenterPoint();
for(int i=;i>;i--)
{
ellipseRect.SetRect(ptCenter,ptCenter);
ellipseRect.InflateRect(i*,i*);
pDC->Ellipse(ellipseRect);
}

编译运行程序,尝试改变窗口大小,可以发现闪烁现象。

  在双缓冲方法中,首先要做的是屏蔽背景刷新。背景刷新其实是在响应WM_ERASEBKGND消息。我们在视类中添加对这个消息的响应,可以看到缺省的代码如下:

BOOL CMYView::OnEraseBkgnd(CDC* pDC)
{
return CView::OnEraseBkgnd(pDC);
}

是调用父类的OnEraseBkgnd函数,我们屏蔽此调用,只须直接return TRUE;即可。

下面是内存缓冲作图的步骤。

CPoint ptCenter;
CRect rect,ellipseRect;
GetClientRect(&rect);
ptCenter = rect.CenterPoint();
CDC dcMem; //用于缓冲作图的内存DC
CBitmap bmp; //内存中承载临时图象的位图
bmp.CreateCompatibleBitmap(&dcMem,rect.Width(),rect.Height());//创建兼容位图
dcMem.CreateCompatibleDC(pDC); //依附窗口DC创建兼容内存DC
dcMem.SelectObject(&bmp); //将位图选择进内存DC
dcMem.FillSolidRect(rect,pDC->GetBkColor()); //按原来背景填充客户区,不然会是黑色
for(int i=;i>;i--) //在内存DC上做同样的同心圆图象
{
ellipseRect.SetRect(ptCenter,ptCenter);
ellipseRect.InflateRect(i*,i*);
dcMem.Ellipse(ellipseRect);
}
pDC->BitBlt(,,rect.Width(),rect.Height(),&dcMem,,,SRCCOPY);//将内存DC上的图象拷贝到前台
dcMem.DeleteDC(); //删除DC
bm.DeleteObject(); //删除位图

由于复杂的画图操作转入后台,我们看到的是速度很快的复制操作,自然也就消除了闪烁现象。

MFC中的双缓冲技术(解决绘图闪烁问题)的更多相关文章

  1. C#中利用双缓冲技术解决绘图闪屏问题。

    这段时间在做一个小型游戏,在界面显示的时候用到了一些图形.一开始涉及到的图形全都用控件的背景图片代替了.这样游戏运行的时候存在的一个很大的问题是游戏运行很慢.小组成员费尽周折,即将放弃,每一个成员都愁 ...

  2. OpenGL中实现双缓冲技术

    在OpenGL中实现双缓冲技术的一种简单方法: 1.在调用glutInitDisplayMode函数时, 开启GLUT_DOUBLE,即glutInitDisplayMode(GLUT_RGB | G ...

  3. 强制设置双缓冲DoubleBuffered 解决tableLayoutPanel 闪烁

    tableLayoutPanel.GetType().GetProperty("DoubleBuffered", System.Reflection.BindingFlags.In ...

  4. VC 绘图,使用双缓冲技术实现

    VC 绘图,使用双缓冲技术实现 - Cloud-Datacenter-Renewable Energy-Big Data-Model - 博客频道 - CSDN.NET VC 绘图,使用双缓冲技术实现 ...

  5. 【MFC】MFC绘图不闪烁——双缓冲技术

    MFC绘图不闪烁——双缓冲技术[转] 2010-04-30 09:33:33|  分类: VC|举报|字号 订阅 [转自:http://blog.163.com/yuanlong_zheng@126/ ...

  6. 《MFC游戏开发》笔记六 图像双缓冲技术:实现一个流畅的动画

    本系列文章由七十一雾央编写,转载请注明出处.  http://blog.csdn.net/u011371356/article/details/9334121 作者:七十一雾央 新浪微博:http:/ ...

  7. c++双缓冲技术,以避免闪烁绘图

    当数据量非常大时,画图可能须要几秒钟甚至更长的时间,并且有时还会出现闪烁现象,为了解决这些问题.可採用双缓冲技术来画图. 双缓冲即在内存中创建一个与屏幕画图区域一致的对象,先将图形绘制到内存中的这个对 ...

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

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

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

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

随机推荐

  1. clover 显卡注入功能详细讲解

    13 March 2014   GraphicsInjector功能源于变色龙,不过比变色龙更加灵活,定制性更加强大.Intel的显卡 GMA950, X3100, HD300, HD4000被证实可 ...

  2. javascript获取属性的两种方法及区别

    javascript获取属性有两种方式,点或者中括号: var obj={} obj.x=1 console.log(obj.x)//1 第一种方式,x是字面量 try{ console.log(ob ...

  3. Noip2018 考前准备

    目录 基础算法 二分 模拟(未补) 高精(未学习) 搜索(未补) 排序 图论 树的直径 树的重心 最短路算法 Spfa Dijkstra Floyd 最小生成树 kruskal 数论 线性筛 线性筛素 ...

  4. python中的decorator的作用

    1.概念 装饰器(decorator)就是:定义了一个函数,想在运行时动态增加功能,又不想改动函数本身的代码.可以起到复用代码的功能,避免每个函数重复性编写代码,简言之就是拓展原来函数功能的一种函数. ...

  5. (转) 改变UITextField placeHolder颜色、字体 、输入光标位置等

    我们有时需要定制化UITextField对象的风格,可以添加许多不同的重写方法,来改变文本字段的显示行为.这些方法都会返回一个CGRect结构,制定了文本字段每个部件的边界范围,甚至修改placeHo ...

  6. u-boot顶层Makefile分析

    1.u-boot制作命令 make forlinx_nand_ram256_config: make all; 2.顶层mkconfig分析,参考 U-BOOT顶层目录mkconfig分析 mkcon ...

  7. Codeforces Round #439 (Div. 2) E. The Untended Antiquity

    E. The Untended Antiquity 题目链接http://codeforces.com/contest/869/problem/E 解题心得: 1.1,x1,y1,x2,y2 以(x1 ...

  8. sublime_win配置

    让你用sublime写出最完美的python代码--windows环境 点击上方标题查看原文链接, 感谢大佬 至少很长一段时间内,我个人用的一直是pycharm,也感觉挺好用的,也没啥大毛病 但是py ...

  9. 关于requirejs和grunt压缩合并是否矛盾

    requirejs主要是为了模块化开发,这样带来的好处不言而喻.但是分成多个js文件增加了请求数,那么就要用到合并压缩.合并压缩了原来的许多独立的js模块,那requirejs又是怎么冲压缩的文件中找 ...

  10. 【02】[].slice和Array.prototype.slice

    [02][].slice和Array.prototype.slice 01,Array是一个构造函数.浏览器内置的特殊对象.   02,Array没有slice方法. 03,Array.prototy ...