最近做中国象棋,绘制界面时遇到些问题,绘图过程中屏幕闪烁,估计都会想到利用双缓冲来解决问题,但查了下网上双缓冲的资料,发现基本是MFC的,转化为VC++后,大概代码如下:

void DrawBmp(HDC hDC, HBITMAP hBitmap)
{
HDC hdcMEM; //用于缓冲作图的内存DC
HBITMAP bmp; //内存中承载临时图象的位图
HANDLE hOld;
hdcMEM = CreateCompatibleDC(hDC);//依附窗口DC创建兼容内存DC
bmp = CreateCompatibleBitmap(hDC, , ); //创建与hDC环境相关的设备兼容的位图 SelectObject(hdcMEM, bmp);
hOld = SelectObject(hdcImage, hBitmap); StretchBlt(hDC, , , , , hdcMEM, , , , , SRCCOPY); SelectObject(hdcImage, hOld);
DeleteObject(hOld);
}

但以上代码似乎没有用到hBitmap,当然屏幕上也不会有任何输出,但网上的资料基本一样。查了一番资料,才明白如果hDC中已经有位图数据,BitBlt的时候,就会直接把hDC中的数据画到内存缓冲区里。所以,还需要建一DC,名为hdcImage,把要画的位图选入内存hdcImage中,然后再在内存缓冲区上绘图。

整理代码如下:

void DrawBmp(HDC hDC, HBITMAP hBitmap)
{
HDC hdcImage;
HDC hdcMEM; //注意此处,创建了两个HDC
hdcMEM = CreateCompatibleDC(hDC);
hdcImage = CreateCompatibleDC(hDC);
HBITMAP bmp = ::CreateCompatibleBitmap(hDC, nWidth, nHeight);//创建与hDC环境相关的设备兼容的位图 SelectObject(hdcMEM, bmp); SelectObject(hdcImage, hBitmap);//注意此处,将要画的位图选入hdcImage StretchBlt(hdcMEM, , , , , hdcImage, , , , , SRCCOPY); //这里才能正常画图,将hdcImage中的位图直接复制到内存缓冲区
StretchBlt(hDC, , , , , hdcMEM, , , , , SRCCOPY); //再将内存缓冲区中的数据绘制到屏幕上. DeleteObject(hdcImage); }

当然,要注意的一点就是,如果要绘制多张图片,比如两张,如果大家这样调用:
DrawBmp(hDC, hBitmap1);
DrawBmp(hDC, hBitmap2);
依然会发生闪烁,下面解释原因:
举个例子,屏幕绘图就像现场作画,如果两次调用绘图函数,就相当于在观众面前作画,第一次画第一张(例如中国象棋的背景)。第二次画第二张(如棋盘)。这样,在画背景和棋盘时,由于颜色有反差,必然在贴第二张图时会发现闪烁,这样利用双缓冲相当于没用,还浪费了内存空间。

双缓冲的原理是:在内存中先把第一张图画好,此时不要转画到屏幕上,然后继续在原来的内存中画第二张,等把所有的图全画好后,再一次性贴到屏幕上。那样内存中存在的就是完整的图形,观众看不到绘图的过程,只能看到绘图的结果,而最后是一次性复制到屏幕上的,当然不会发生闪烁现象。

为了更好解释双缓冲的原理,附图片如下:

PS:以上照片来自网络,只为能更好理解,本人无意侵权。

在以上代码的基础上作如下更改:

void DrawBmp(HDC hDC, HBITMAP hBitmap) //此处返回类型改为HDC
{
HDC hdcMEM;
hdcMEM = CreateCompatibleDC(hDC); SelectObject(hdcMEM, hBitmap); //将位图选择进内存DC StretchBlt(hDC, , , , , hdcMEM, , , , , SRCCOPY);//这里才能正常画图,将hdcImage中的位图直接复制到内存缓冲区 DeleteObject(hdcMEM);
}

调用以上函数在内存中画第一张图:
DrawBmp(hdcTmp , hBitmap1);
画第二张图
DrawBmp(hdcTmp, hBitmap2); //此时传的为hdcTmp,其中hdcTmp中已经有第一张图片的数据,此次调用后就会把第二张图片绘到原来的基础上。

如果要画多张图,就依次调用本函数绘制,记得一定要把所有的图全画到一个设备DC上,最后再一次性画到屏幕上,才不会出现闪烁现象。
等把所有图全画到hdcTmp中后,hdcTmp中已经有了完整的图形,再把完整的图形绘制到屏幕上:
BitBlt(hDC, 0, 0, 100, 100, hdcTmp, 0, 0, SRCCOPY); //此处第一个参数才为hDC,即窗口句柄

至此,双缓冲画多幅图绘制完毕。

VC++绘图时,利用双缓冲解决屏幕闪烁 转载的更多相关文章

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

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

  2. Android 绘图时实现双缓冲

    一.双缓冲技术原理: 在内存中创建一片内存区域,把将要绘制的图片预先绘制到内存中,在绘制显示的时候直接获取缓冲区的图片进行绘制.更具体一点来说:先通过setBitmap方法将要绘制的所有的图形绘制到一 ...

  3. MFC双缓冲解决图象闪烁[转]

    转载网上找到的一篇双缓冲的文章,很好用.http://www.cnblogs.com/piggger/archive/2009/05/02/1447917.html__________________ ...

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

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

  5. 双缓冲解决控制台应用程序输出“闪屏”(C/C++,Windows)

    使用 C 语言编写游戏的小伙伴们想必起初都要遇到这样的问题,在不断清屏输出数据的过程中,控制台中的输出内容会不断地闪屏.出现这个问题的原因是程序对数据处理花掉的时间影响到了数据显示,或许你可以使用局部 ...

  6. 【MFC】利用双缓冲和随机函数rand()实现蒲公英飞舞

    原始日期:2014-05-29 22:44 这几天有些懒,几乎没怎么学MFC了,好容易有个题目:用双缓冲实现蒲公英飞舞,想来想去也没想到好方法,索性动手开始 写了 ,这一写,得,出来了,呵呵,无意中产 ...

  7. Java中用双缓冲技术消除闪烁

    在Java编写具有连贯变化的窗口程序时,通常的办法是在子类中覆盖父类的paint(Graphics)方法,在方法中使用GUI函数实现窗口重绘的过程.连贯变换的窗口会不断地调用update(Graphi ...

  8. HTML5_canvas_图片加载_双缓冲_跳帧闪烁问题

    canvas 图片加载 pen.drawImage(ele, showX, showY, imgWidth, imgHeight); ele    将 img 元素 加载到画布上 步骤 1. 创建一个 ...

  9. Delphi 使用双缓冲解决图片切换时的闪烁问题 good

    var TempCanvas: TCanvas; BufDC: HDC; BufBitmap: HBITMAP; begin // 创建一个与显示设备兼容的内存设备 BufDC := CreateCo ...

随机推荐

  1. codeforces mysterious present 最长上升子序列+倒序打印路径

    link:http://codeforces.com/problemset/problem/4/D #include <iostream> #include <cstdio> ...

  2. Microsoft .NET Framework NGEN是神马东东?

    简单的说,如果你的程序是基于.net framework的托管代码的话,NGEN服务能让你的程序第二次打开的速度变快. 赶脚是非常pad化的一项服务. http://msdn.microsoft.co ...

  3. [Hibernate] - Generic Dao

    使用泛型写了一个通用的Hibernate DAO类. GenericDao接口 package com.my.dao; import java.io.Serializable; import java ...

  4. SQL2005 : 如何在SQL Server Profiler (事件查看器)中 跟踪查看死锁恢复

    SQL Profiler 通过 SQL Profiler 工具程序,可监控应用程序如何访问数据库引擎.普通来说,当系统性能需要优化或是应用程序对数据库访问的结果不合预期,都可以使用该工具确认视图问题所 ...

  5. Windows下用C++删除磁盘分区信息

    做一个能对U盘重新分区的小工具,使用该方法删除U盘中原有的分区表. bool CCesDiskDll::DestroyDisk(unsigned char deviceNumber) { DWORD ...

  6. vi编辑器的基本使用

      进入vi为命令模式,需要按 i/a/o 键进入插入模式(在左下角最后一行有“-- INSERT --”字样). i:光标所在位置,进行输入(相似命令cw) a:光标所在位置的下一个位置,进行输入o ...

  7. 不使用spring的情况下原生java代码两种方式操作mongodb数据库

    由于更改了mongodb3.0数据库的密码,导致这几天storm组对数据进行处理的时候,一直在报mongodb数据库连接不上的异常.   主要原因实际上是和mongodb本身无关的,因为他们改的是配置 ...

  8. 欢迎进入Node.js世界

    官网上(http://www.nodejs.org )给Node下的定义是:”一个搭建在Chrome JavaScript 运行时上的平台,用于构建高速.可伸缩的网络程序.Node.js采用的事件驱动 ...

  9. matlab示例程序--Motion-Based Multiple Object Tracking--卡尔曼多目标跟踪程序--解读

    静止背景下的卡尔曼多目标跟踪 最近学习了一下多目标跟踪,看了看MathWorks的关于Motion-Based Multiple Object Tracking的Documention. 官网链接:h ...

  10. php配置

    在 php.ini 文件中设置 cgi.fix_pathinfo=0 ,能避免掉很多不必要的 stat() 系统调用.