博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
VC++绘图时,利用双缓冲解决屏幕闪烁 转载
阅读量:5888 次
发布时间:2019-06-19

本文共 2321 字,大约阅读时间需要 7 分钟。

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

void DrawBmp(HDC hDC, HBITMAP hBitmap){     HDC hdcMEM; //用于缓冲作图的内存DC     HBITMAP bmp; //内存中承载临时图象的位图     HANDLE hOld;     hdcMEM = CreateCompatibleDC(hDC);//依附窗口DC创建兼容内存DC     bmp = CreateCompatibleBitmap(hDC, 100, 100); //创建与hDC环境相关的设备兼容的位图     SelectObject(hdcMEM, bmp);     hOld = SelectObject(hdcImage, hBitmap);     StretchBlt(hDC, 0, 0, 100, 100, hdcMEM, 0, 0, 100, 100, 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, 0, 0, 100, 100, hdcImage, 0, 0, 100, 100, SRCCOPY); //这里才能正常画图,将hdcImage中的位图直接复制到内存缓冲区     StretchBlt(hDC, 0, 0, 100, 100, hdcMEM, 0, 0, 100, 100, 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, 0, 0, 100, 100, hdcMEM, 0, 0, 100, 100, 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,即窗口句柄

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

 

转载地址:http://vdgix.baihongyu.com/

你可能感兴趣的文章
【总结整理】面试需了解
查看>>
ArcEngine开发遇到的问题(转)
查看>>
js时间戳与日期格式的相互转换
查看>>
关于RF在实践WEB UI自动化测试时,碰到的问题
查看>>
解决Maven项目中jar包依赖冲突问题
查看>>
Pairing Heap模板
查看>>
2016的ChinaJoy沦为ChinaVR?
查看>>
Unity Shaders and Effets Cookbook
查看>>
cairo-1.14.6 static compiler msys mingw32
查看>>
Mac osx 下让android 模拟器横屏
查看>>
SQL创建触发器
查看>>
喜爱看剑雨,数据流的本人对各主角…
查看>>
luogu P1387 最大正方形
查看>>
Android图片圆角效果
查看>>
MSSQL跨服务器数据库查询
查看>>
WeChat Official Account Admin Platform API Introduction
查看>>
C语言写单链表的创建、释放、追加(即总是在最后的位置增加节点)
查看>>
poj1635
查看>>
C# LINQ详解(一)
查看>>
视频直播点播nginx-rtmp开发手册中文版
查看>>