在编写win32 GUI相关的程序的时候,最直接的方法是使用GDI API进行绘制操作。一般为了图形绘制过程中为避免绘制过程闪动,而多采用双Buffer的做法,具体是先在一个内存DC中线将图像绘制好,然后采用BitBlt函数将该内存DC中绘制好的图像贴到目标DC中(该目标DC即是待绘制窗口的DC)。在内存DC中绘图的时候,需先创建该DC,然后根据需要创建各种Pen,各种Brush,将Pen/Brush选进去,绘制完成之后,再将原来的Pen/Brush选回去,最后执行InvalidateRect函数使窗口中的指定区域无效,触发WM_PAINT消息,在响应WM_PAINT消息中,执行BitBlt函数。
该过程使用GDI函数形式的API,操作起来不是很方便,好在Windows给我们提供了一个更好的选择,那就是Gdiplus,在提供相同基本功能前提下,C++对象形式的API使用起来更加方便,而且还提供了常见的变换API,让相关的图形绘制操作变得更省心了。
这里仅介绍在Gdiplus过程中如何实现爱GDI中类似的双Buffer绘图功能,其核心实现是使用Graphics这个对象。先看其构造函数定义,如下
1 Graphics(hdc) 2 Graphics(hdc, hdevice) 3 Graphics(hwnd, icm) 4 Graphics(image)
从其构造函数可以看出,Graphics对象的绘制过程,可以在的DC上进行,可以在窗口上进行,也可以在一个Image对象上进行,形式非常的灵活,此处实现双Buffer绘制即是利用这一灵活性,另外对应还用到的还有Graphics对象的DrawImage方法,该方法可以将一个Image对象,绘制到构造函数所提供的上下文里头去。如此不难看出此处的双Buffer绘制的操作过程如下
1,新建一个Image对象,命名为men_image,该对象用于在内存中保存绘制结果
2,新建一个Graphics对象,命名为drawer,构造函数传入mem_image
3,使用drawer进行各项所需的绘制过程,结果保存到mem_image中
4,使用InvalidateRect函数是制定窗口中的区域无效,触发WM_PAINT消息
5,在响应WM_PAINT消息中,使用另外一个Graphics对象,该对象可以是一个临时对象(构造函数传入HDC),或持续存在的对象(构造函数传入HWND),然后利用Graphics::DrawImage,将mem_image对象显示到窗口中。
如此处理的话,实现了将绘制过层(drawer完成的)与显示过程(响应WM_PAINT过程)相分离,绘制过程不需关心显示过程,各自的功能内聚,降低了耦合,简化了各自内部的实现流程。
PS: 在VS2010中使用Gdiplus的代码,以下头文件必须放在文件首部,再引用其他头文件,否则编译不过,Faint!
#include <windows.h>
#include <gdiplus.h>