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

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

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. iOS开发——AFNetworking基于https的使用

    应公司项目需求,之前的项目使用的http,新项目要求使用https,这篇博客是在AFNetworking框架基于http的基础上修改而来. 1.在开始前,先要把 .crt 文件转成 .cer 文件,然 ...

  2. luogu P3765 总统选举(线段树维护摩尔投票+平衡树)

    这题需要一个黑科技--摩尔投票.这是一个什么东西?一个神奇的方法求一个序列中出现次数大于长度一半的数. 简而言之就是同加异减: 比如有一个代表投票结果的序列. \[[1,2,1,1,2,1,1]\] ...

  3. IDEA中编写脚本并运行shell脚本

    IDEA中编写脚本并运行shell脚本     来自 <https://blog.csdn.net/u012443641/article/details/81295999>

  4. MySQL锁定状态查看命令

    1 show processlist; SHOW PROCESSLIST显示哪些线程正在运行.您也可以使用mysqladmin processlist语句得到此信息.如果您有SUPER权限,您可以看到 ...

  5. chrome默认打开隐身模式

    chrome图标右键属性,在“目标”后添加参数“ --incognito”(注意是双短划线,不包括双引号,双短划线前加一空格)就可以直接以隐身模式启动chrome了

  6. 基于json数据格式实现的简单数据库——jsonDB

    已在github上建立项目:https://github.com/ThinkerCodeChina/jsonDB /** +-------------------------------------- ...

  7. 基于Masonry自己主动计算cell的高度

    /** * This is a very very helpful category for NSTimer. * * @author huangyibiao * @email huangyibiao ...

  8. 走进 CPU 的 Cache

    看了上一篇文章.你可能非常想知道,为什么程序的执行结果会是这样.如今,就让我们来走进 CPU 的世界. 在 SMP(对称多处理器)时代,多个 CPU 一起工作.使运算能力进一步提升,那么CPU 是怎样 ...

  9. 可能是东半球最全的RxJava使用场景小结

    一.Scheduler线程切换 这样的场景常常会在"后台线程取数据,主线程展示"的模式中看见 Observable.just(1, 2, 3, 4) .subscribeOn(Sc ...

  10. invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause

    Column 'dbo.tbm_vie_View.ViewID' is invalid in the select list because it is not contained in either ...