Board logo

标题: 【CAPI】GUI开发2:内存缓冲 [打印本页]

作者: defanive    时间: 2012-11-26 08:18     标题: 【CAPI】GUI开发2:内存缓冲

By Defanive

通过上次GUI开发1的教程,已经可以做出很精美的画面了
接下来我们通过一段代码来引入这一次的目的
在上一次教程的结束代码中,我们做出了图标从左往右移动的代码
假设我们正在做复杂的绘图工程,绘图计算需要一定的耗时
我们在绘图操作前使用API Sleep来模拟这种计算耗时
  1. @echo off
  2. CAPI
  3. set CAPI=API Call user32 LoadImageW ;0 $1.ico ;1 ;0 ;0 ;16
  4. set hIcon=%CAPI_Ret%
  5. set CAPI=API Call kernel32 GetConsoleWindow
  6. set hCMD=%CAPI_Ret%
  7. set CAPI=API Call user32 GetDC ;%hCMD%
  8. set hDC=%CAPI_Ret%
  9. set x=0
  10. :loop
  11. color 07
  12. set CAPI=API Call kernel32 Sleep ;10
  13. set CAPI=API Call user32 DrawIconEx ;%hDC% ;%x% ;0 ;%hIcon% ;32 ;32 ;0 ;0 ;3
  14. set CAPI=API Call kernel32 Sleep ;20
  15. set /a x+=2
  16. goto loop
复制代码
运行批处理,就可以看到闪烁十分严重

为了避免闪烁,就引入了内存缓冲的概念
绘制过程中,先暂时把图像绘制到内存中
全部绘制完毕了,再一次性将全部图像复制到屏幕上
这样就实现了无闪烁效果,也就是内存缓冲的目的

既然要在内存中画图,我们就需要创建一个内存中的DC
为了最后能把内存DC的内容复制到CMD窗口DC上,我们需要让这两个DC兼容
使用API CreateCompatibleDC我们可以根据CMD窗口的DC创建一个兼容的内存DC,并返回其句柄
  1. set CAPI=API Call gdi32 CreateCompatibleDC ;%hDC%
  2. set hDCMem=%CAPI_Ret%
  3. echo %hDCMem%
复制代码
我们创建了一个与CMD窗口DC兼容的内存DC,其句柄保存在hDCMem变量中

有了“画布”DC,但是没有画纸是无法进行绘图的
于是我们要创建一个Bitmap,同样的也要与CMD窗口的DC兼容
使用API CreateCompatibleBitmap可以根据CMD窗口的DC创建一个兼容的Bitmap,并返回其句柄
创建Bitmap的时候我们会需要指定这个Bitmap的大小,再次我们指定创建一个320x320大小的Bitmap
  1. set CAPI=API Call gdi32 CreateCompatibleBitmap ;%hDC% ;320 ;320
  2. set hBMPMem=%CAPI_Ret%
  3. echo %hBMPMem%
复制代码
于是我们创建了一个与CMD窗口DC兼容的Bitmap,并保存在了hBMPMem变量中

我们创建了内存DC,也创建了内存Bitmap
接下来就是要把Bitmap放到DC里面,以便进行画图操作
使用API SelectObject可以把对象放入到DC里,在此我们把内存Bitmap放到内存DC里
  1. set CAPI=API Call gdi32 SelectObject ;%hDCMem% ;%hBMPMem%
复制代码
现在我们的内存缓冲已经准备好了
我们把上面的代码和上一个例程的代码整合一下
同时把所有绘图操作的目标DC都从CMD窗口DC换成内存DC
在此由于color命令只对CMD窗口DC有效,所以我们换用API Rectangle进行清理
API Rectangle会在指定DC中使用画笔和画刷填充一个矩形区域
下面是loop标签内的代码
  1. :loop
  2. set CAPI=API Call gdi32 Rectangle ;%hDCMem% ;0 ;0 ;320 ;320
  3. set CAPI=API Call user32 DrawIconEx ;%hDCMem% ;%x% ;0 ;%hIcon% ;32 ;32 ;0 ;0 ;3
  4. set CAPI=API Call kernel32 Sleep ;20
  5. set /a x+=2
  6. goto loop
复制代码
我们把全部对hDC的操作都改成了对hDCMem操作
于是我们实现了把绘图过程全部放在了内存中进行

现在我们的全部绘图过程都画在了内存DC中
最后一步就是绘图完成之后把内存DC的内容复制到CMD窗口DC上
通过API BitBlt可以把一个DC中的内容复制到另外一个DC中
整个例程代码如下
  1. @echo off
  2. CAPI
  3. set CAPI=API Call user32 LoadImageW ;0 $1.ico ;1 ;0 ;0 ;16
  4. set hIcon=%CAPI_Ret%
  5. set CAPI=API Call kernel32 GetConsoleWindow
  6. set hCMD=%CAPI_Ret%
  7. set CAPI=API Call user32 GetDC ;%hCMD%
  8. set hDC=%CAPI_Ret%
  9. set CAPI=API Call gdi32 CreateCompatibleDC ;%hDC%
  10. set hDCMem=%CAPI_Ret%
  11. set CAPI=API Call gdi32 CreateCompatibleBitmap ;%hDC% ;320 ;320
  12. set hBMPMem=%CAPI_Ret%
  13. set CAPI=API Call gdi32 SelectObject ;%hDCMem% ;%hBMPMem%
  14. set x=0
  15. :loop
  16. set CAPI=API Call gdi32 Rectangle ;%hDCMem% ;0 ;0 ;320 ;320
  17. set CAPI=API Call user32 DrawIconEx ;%hDCMem% ;%x% ;0 ;%hIcon% ;32 ;32 ;0 ;0 ;3
  18. set CAPI=API Call gdi32 BitBlt ;%hDC% ;0 ;0 ;320 ;320 ;%hDCMem% ;0 ;0 ;13369376
  19. set CAPI=API Call kernel32 Sleep ;20
  20. set /a x+=2
  21. goto loop
复制代码
API BitBlt的参数稍微复杂
第1、6个参数为目标DC和源DC,再次为CMD窗口的DC和内存DC
第2、3个参数为目标DC的目标坐标x和y,也就是复制到哪里,在此我们把内存DC的内容复制到CMD窗口DC的(0,0)处,也就是左上角
第4、5个参数为复制的大小宽和高,在此我们把内存DC中的全部内容都复制过去,因此我们给参数320 320
第7、8个参数为源DC的源坐标x和y,也就是从源DC的哪里开始复制,在此我们从左上角开始复制,也就是0 0
最后一个参数为操作方法,其值可以参考MSDN,再次我们选择SRCCOPY,也就是复制内容,值为0xCC0020,也就是13369376

运行批处理,我们可以看到图像绘制非常平滑,没有闪烁
这对于大型的GUI开发程序是非常有实用性的
大型程序绘图分多层进行,如背景、角色、文字、遮罩等等
如果没有内存缓冲将会有非常严重的闪烁
内存缓冲解决闪烁是非常有效的

链接: https://pan.baidu.com/s/1XQakFk2fDSft2I69kdOmgg?pwd=7hkn
作者: ht河豚    时间: 2012-11-27 23:17

顶一下,好贴,学到了很多
作者: 转世燕    时间: 2015-11-28 15:44

一起收了。。。。




欢迎光临 批处理之家 (http://bathome.net./) Powered by Discuz! 7.2