最近做中国象棋,绘制界面时遇到些问题,绘图过程中屏幕闪烁,估计都会想到利用双缓冲来解决问题,但查了下网上双缓冲的资料,发现基本是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. 更新EF,EF 报错

    在项目中,对一个视图进行了更新,增加了一个字段,然后需要更新EF访问,可是往往会报错, 查看映射关系发现EF将字段映射为主键,而视图没有进行ISNULL处理. 可以有两种处理方式: 1:修改视图对字段 ...

  2. linux之"server" directive is not allowed here in

    配置完rewrite之后重启nginx发现如下错误 "server" directive is not allowed here in* 原因是因为 外部配置的simple.con ...

  3. MSSQL 和 REDIS的数据类型对应关系

    when user_type_id in (34) then 'BLOB' --image            when user_type_id in (35) then 'CLOB' --tex ...

  4. 【redis】 redis 创建集群时,Waiting for the cluster to join.... 一直等待

    redis 搭建集群时,一直join.... ./redis-trib.rb  create --replicas 1 127.0.0.1:6379 127.0.0.1:6380 127.0.0.1: ...

  5. Hibernate5.2关联关系之单向一对多(一)

    Hibernate5.2之单向一对多 一. 简介    Hibernate中最复杂的应该就是各种关联(单向一对多.单向多对一.双向一对多.一对一.多对多)关系的映射,于是笔者就想着去写一些关于Hibe ...

  6. (C#) 基本概念一览表

    A abstract class An abstract class is a class that must be inherited and have the methods overridden ...

  7. sqlite_

    应用程序初始化时需要批量的向sqlite中插入大量数据,单独的使用for+Insert方法导致应用响应缓慢,因为 sqlite插入数据的时候默认一条语句就是一个事务,有多少条数据就有多少次磁盘操作.我 ...

  8. LeetCode Implement pow(x, n).

    这个题目我也没有思路,同学们可以查看这个http://www.cnblogs.com/NickyYe/p/4442867.html 下面是我改进后的代码 第一种方法: class Solution { ...

  9. windows Server 2008 IE增强的安全配置关闭方法

    解决方法 开始->管理工具->服务器管理器

  10. C#EXCEL 操作类--C#ExcelHelper操作类

    主要功能如下1.导出Excel文件,自动返回可下载的文件流 2.导出Excel文件,转换为可读模式3.导出Excel文件,并自定义文件名4.将数据导出至Excel文件5.将指定的集合数据导出至Exce ...