双缓冲画图,它是一种主要的图形图像画图技术。首先,它在内存中创建一个与屏幕画图区域一致的对象,然后将图形绘制到内存中的这个对象上,最后把这个对象上的图形数据一次性地拷贝并显示到屏幕上。

这样的技术能够大大地提高画图的速度,降低卡顿和闪屏的问题。

Tip:

去看看吧。1.

我们为什么要使用双缓冲技术来进行画图?

    在应用程序开发中,当图像信息数据量非常大时。画图可能须要几秒钟甚至更长的时间,这时。应用程序可能会出现卡顿的现象。另外,假设窗体在响应WM_PAINT消息的同一时候也要进行复杂的图形处理。那么窗体在重绘时就会由于频繁的刷新而引起闪烁现象。而使用双缓冲技术就能有效地解决以上问题。

闪烁问题:

    窗体在刷新时,总要有一个擦除原来图象的过程OnEraseBkgnd,它利用背景色填充窗体画图区,然后再调用新的画图代码进行重绘。这样一擦一写造成了图象颜色的反差。当WM_PAINT的响应非常频繁的时候,这样的反差也就越发明显。

于是我们就看到了闪烁现象。

假设仅仅是仅仅去掉背景色的填充。的确不管如何重画图形都不会闪了。可是那样的话,窗体画面往往会变的乱七八糟。由于每次绘制图象的时候都没有将原来的图象清除,造成了图象的残留。叠加了新图形。

所以单纯的禁止背景重绘是不够的,我们还要进行又一次画图。

画图函数可使用 BitBlt。它支持图形块的复制。速度非常快。

双缓冲画图实现方式:

    首先把要显示的图形先在内存中绘制好。然后再一次性地将内存中的图形一个点一个点地覆盖到屏幕上去(这个过程非常快,由于是非常完整的内存拷贝),以至于用背景色擦除界面后再贴图到屏幕上也不会闪烁了。

    步骤:

  1. 在内存中创建与画布一致的缓冲区;
  2. 在缓冲区画图;
  3. 将缓冲区位图复制到当前画布并显示到屏幕上;
  4. 释放内存缓冲区。

流程图:

代码实现:

    这里在VC++开发平台使用MFC开发,一般在OnDraw和OnPaint函数中进行图像绘制。

    首先屏蔽背景刷新,背景刷新事实上是在响应WM_ERASEBKGND消息。我们仅仅要把OnEraseBkgnd函数返回值改为TRUE即可了。

//`直接画图`,这里重绘会出现卡顿现象
void CDoubleBufferDlg::DrawItem(CDC* pDC)
{
ASSERT_VALID(pDC); CRect rcClient;
pDC->GetClipBox(rcClient); CPen pen(PS_SOLID, 1, RGB(178,178,178));
CPen* pOldPen = NULL; pOldPen = pDC->SelectObject(&pen); pDC->Ellipse(rcClient); for(int j=0;j<1000;j++)
{
pDC->MoveTo(0,0);
pDC->LineTo(rcClient.Width(),rcClient.Height()); pDC->MoveTo(rcClient.Width(),0);
pDC->LineTo(0,rcClient.Height());
} //画图完毕后的清理
pDC->SelectObject(pOldPen);
pOldPen->DeleteObject();
}
//`双缓冲画图`
void CDoubleBufferDlg::DrawItemWithDoubleBuffer(CDC* pDC)
{
ASSERT_VALID(pDC); CRect rcClient;
pDC->GetClipBox(rcClient); // 定义一个内存显示设备上下文对象
CDC MemDC; // 定义一个GDI位图对象
CBitmap MemBitmap; // 创建一个与指定设备(这里是屏幕)兼容的内存设备上下文环境(DC)
MemDC.CreateCompatibleDC(pDC); // 建立一个与屏幕显示兼容的位图,位图的大小可选用窗体客户区的大小
MemBitmap.CreateCompatibleBitmap(pDC, rcClient.Width(), rcClient.Height()); // 将位图对象选入到内存显示设备上下文中。仅仅有选择了才干进行画图
CBitmap *pOldBit = MemDC.SelectObject(&MemBitmap); // 先用白色背景色将位图清除干净,否则是黑色。
MemDC.FillSolidRect(0, 0, rcClient.Width(), rcClient.Height(), RGB(255,255,255)); // 定义画笔。颜色为灰色
CPen pen(PS_SOLID, 1, RGB(178,178,178));
CPen* pOldPen = NULL; // 把画笔对象选定到指定的设备上下文环境中
pOldPen = MemDC.SelectObject(&pen); //-----------------------------------------画图操作
// 需放在BitBlt函数前 // 画椭圆
MemDC.Ellipse(rcClient); // 画对角线,循环次数多,没有双缓冲会卡顿
for(int i=0;i<1000;i++)
{
MemDC.MoveTo(0,0);
MemDC.LineTo(rcClient.Width(), rcClient.Height()); MemDC.MoveTo(rcClient.Width(), 0);
MemDC.LineTo(0, rcClient.Height());
}
//-----------------------------------------画图操作 // 将内存中的图复制到屏幕上进行显示
pDC->BitBlt(0, 0, rcClient.Width(), rcClient.Height(), &MemDC, 0, 0, SRCCOPY); // 画图完毕后的清理
MemDC.SelectObject(pOldPen);
MemDC.SelectObject(pOldBit); //使用GetDC()要用ReleaseDC
::ReleaseDC(this->m_hWnd, MemDC);
pOldPen->DeleteObject();
MemBitmap.DeleteObject();
}

效果图:

知识概念(摘自百度百科):

GDI

    在Windows操作系统下,绝大多数具备图形界面的应用程序都离不开GDI,我们利用GDI所提供的众多函数就能够方便的在屏幕、打印机及其他输出设备上输出图形,文本等操作。那我们GDI究竟是什么呢?

    GDI是Graphics Device Interface的缩写,含义是图形设备接口,它的主要任务是负责系统与画图程序之间的信息交换,处理全部Windows程序的图形输出。它的出现使程序猿无须要关心硬件设备及设备驱动。就能够将应用程序的输出转化为硬件设备上的输出,实现了程序开发人员与硬件设备的隔离,大慷慨便了开发工作。GDI有下面几个特点:

  1. 不同意程序直接訪问物理显示硬件。通过称为“设备环境(DC)”的抽象接口间接訪问显示硬件。
  2. 程序须要与显示硬件(显示器、打印机等) 进行通讯时,必须首先获得与特定窗体相关联的设备环境。
  3. 用户无需关心详细的物理设备类型。
  4. Windows參考设备环境的数据结构完毕数据的输出。

以上的设备环境,就是我们的DC(device context)。

DC(device context)

    在Windows环境中,各程序的输出必须限制在自己的窗体中。

GDI用一种简单的机制保证在窗体中画图的各程序遵循这个规则。

这样的机制即为设备描写叙述表(DC);当Windows程序在屏幕、打印机或其他设备上画图时,它并非将像素直接输出到设备上,而是将图绘制到由设备描写叙述表表示的逻辑意义上的”显示平面”上去。设备描写叙述表是深寓于Windows中的一种数据结构,它包含GDI须要的全部关于显示平面情况的描写叙述字段。包含相连的物理设备和各种各样的状态信息。

    设备描写叙述表,又称为设备上下文。或者设备环境,它是一个定义一组图形对象(画笔等等)及其属性、影响输出的图形方式(数据)结构。windows提供设备描写叙述表。用于应用程序和物理设备之间进行交互,从而提供了应用程序设计的平台无关性。

    设备描写叙述表是一种数据结构,它包含了一个设备(如显示器和打印机)的绘制属性相关的信息。全部的绘制操作通过设备描写叙述表进行。设备描写叙述表与大多 WIN32结构不同,应用程序不能直接訪问设备描写叙述表,仅仅能由各种相关API函数通过设备描写叙述表的句柄间接訪问该结构。

    设备描写叙述表总是与某种系统硬件设备相关。

比方屏幕设备描写叙述表与显示设备相关。打印机设备描写叙述表与打印设备相关等等。

屏幕设备描写叙述表。一般我们简单地称其为设备描写叙述表。它与显示设备具有一定的相应关系。在windows GDI界面下。它总是相关于某个窗体或这窗体上的某个显示区域。

通常意义上窗体的设备描写叙述表。一般指的是窗体的客户区,不包含标题栏、菜单条所占有的区域,而对于整个窗体来说,其设备描写叙述表严格意义上来讲应该称为窗体设备描写叙述表。它包含窗体的全部显示区域。二者的操作方法全然一致,所不同的仅仅是可操作的范围不同而已。

    windows 窗体一旦创建,它就自己主动地产生了与之相相应的设备描写叙述表数据结构,用户可运用该结构。实现对窗体显示区域的GDI操作,如划线、写文本、绘制位图、填充等。而且全部这些操作均要通过设备描写叙述表句柄来进行。


  1. 这是第一次用 Markdown博客,故借用脚注纪念一下吧。哈哈!

VC双缓冲画图技术介绍的更多相关文章

  1. 【MFC】MFC绘制动态曲线,用双缓冲绘图技术防闪烁

    摘自:http://zhy1987819.blog.163.com/blog/static/841427882011614103454335/ MFC绘制动态曲线,用双缓冲绘图技术防闪烁   2011 ...

  2. C#-gdi画图,双缓冲画图,Paint事件的触发---ShinePans

    在使用gdi技术画图时,有时会发现图形线条不够流畅,或者在改变窗口大小时会闪烁不断的现象.(Use DoubleBuffer to solve it!)                         ...

  3. c# GDI画图 双缓冲画图分析

    双缓冲绘图分析  1.Windows 绘图原理  我们在 Windows 环境下看到各种元素,如菜单.按钮.窗口.图像,从根本上说,都是“画”出来的.这时的屏幕,就相当于一块黑板,而 Windows ...

  4. [转载] MFC绘制动态曲线,用双缓冲绘图技术防闪烁

    转载的原文地址 先上效果图 随着时间的推移,曲线向右平移,同时X轴的时间坐标跟着更新. 一.如何绘制动态曲线 所谓动画,都是一帧一帧的图像连续呈现在用户面前形成的.所以如果你掌握了如何绘制静态曲线,那 ...

  5. win32下的双缓冲绘图技术

    一:双缓冲原理 为了解决窗口刷新频率过快所带来的闪烁问题,利用双缓冲技术进行绘图.所谓双缓冲技术,就是将资源加载到内存,然后复制内存数据到设备DC(这个比较快),避免了直接在设备DC上绘图(这个比较慢 ...

  6. VC++双缓冲保持背景不擦除之实现

    几天前,我终于克服了C++窗体重绘时的闪烁问题,用到的技巧就是双缓冲.但是怎样保持住已经绘制的图形呢?也就是仿照Windows自带的画图程序一般,动态的做出一条直线.最容易想到的方法是在MouseMo ...

  7. [Android学习笔记]双缓冲绘图技术

    双缓冲技术绘图: 什么情况下产生的双缓冲技术?当数据量很大时,绘图可能需要花费很长的时间,这样屏幕就会出现卡顿,闪烁等现象. 什么是双缓冲技术?双缓冲是在内存中创建一个与屏幕绘制区域一致的对象,先将图 ...

  8. Win32下双缓冲绘图技术

    一:双缓冲原理 为了解决窗口刷新频率过快所带来的闪烁问题,利用双缓冲技术进行绘图.所谓双缓冲技术,就是将资源加载到内存,然后复制内存数据到设备DC(这个比较快),避免了直接在设备DC上绘图(这个比较慢 ...

  9. MFC VC 双缓冲绘图基本原理与实现,详细解释

    转自:http://blog.csdn.net/foreverhuylee/article/details/21548107 当然你可以直接搜索到能用的代码,并且基本能满足要求.不过这样总不是学习的态 ...

随机推荐

  1. layui计算剩余时间

    <div id="test"></div> <script> layui.use('util', function(){ var util = ...

  2. sql拼接

    with t as( select 'Charles' parent, 'William' child union select 'Charles', 'Harry' union select 'An ...

  3. System.getProperty可以获取的参数

    java.version Java 运行时环境版本 java.vendor Java 运行时环境供应商 java.vendor.url Java 供应商的 URL java.home Java 安装目 ...

  4. 【BZOJ4071】【APIO2015】巴邻旁之桥

    题意: Description 一条东西走向的穆西河将巴邻旁市一分为二,分割成了区域 A 和区域 B. 每一块区域沿着河岸都建了恰好 1000000001 栋的建筑,每条岸边的建筑都从 0 编号到 1 ...

  5. Python学习————集合的增删查

    可变的数据类型,他里面的元素必须是不可变的数据类型.无序,内容不能重复.应用于去重 增加:set1.add('元素')--->将元素无序的插入集合set1中set1.update("元 ...

  6. 紫书 习题8-12 UVa 1153(贪心)

    本来以为这道题是考不相交区间, 结果还专门复习了一遍前面写的, 然后发现这道题的区间是不是 固定的, 是在一个范围内"滑动的", 只要右端点不超过截止时间就ok. 然后我就先考虑有 ...

  7. 洛谷P5087 数学

    DP. 设f[i][j]为前j个数中选i个数的所有组合的分数之和 决策: 不选这个数,得分为f[i][j - 1] 选这个数,得分为f[i - 1][j - 1] * a[j] 可以得到状态转移方程为 ...

  8. Object-C,数组NSArray

    晚上回来,写了2个iOS应用程序. 就是在界面中,展示标签.一种是手动构造界面,然后绑定事件.另外一种是,使用自带的界面作为容器,但是手动向里面放其它界面元素. 书中的观点是,使用图形化界面,构造界面 ...

  9. Docker学习总结(9)——Docker常用命令

    容器生命周期管理 - docker [run|start|stop|restart|kill|rm|pause|unpause] 容器操作运维 - docker [ps|inspect|top|att ...

  10. lower_bound与upper_bound

    昨天一道题目用了lower_bound,大致了解了lower_bound指的是第一个>=x的位置.但是之前对于upper_bound有误解,其实upper_bound指的是第一个>x的位置 ...