这一篇是针对推箱子小游戏写的,有很多细节在其它文章已记录,但还是再写一篇,我一直觉得知识需要反反复复的锤炼才能理解,尤其对于windows程序设计,它不难,但是非常琐碎!每一句代码都有其意思,为什么这样为什么那样,一句代码不明白,就是一个知识点不明白,能允许不能解释的代码存在吗?我们总要给其一个解释,至少能自圆其说!
首先考虑的是位图怎么显示在屏幕上。
当获取或创建一个设备对象时,该设备对象中包含有一个位图,该位图所使用的内存是输出设备在输出图形时所使用的内存(例如,显示器的显示缓冲区),这样,GDI函数在该内存中所绘制的图形同时可以在显示器上可见。
这段话的意思大概是,如果不进行任何的操作,只是得到一个hdc显示位图,位图就处在显示器的显示缓冲区中。
接下来就是内存设备对象,也就是在内存中创建一个设备对象,在这个设备对象上画图,然后再把这个位图送到其它显示设备上显示。唯一需要的是,创建的这个内存设备对象得兼容其它的显示设备对象,比如hdc等等。
这里需要注意的一个问题,创建内存设备对象初始时,其位图尺寸只有1x1(即一个像素),需要扩大显示表面才能容纳位图,采用的方法是创建一个兼容位图去填充内存设备对象。如图所示:
针对推箱子游戏的代码:
hdc=GetDC(hWnd); mdc=CreateCompatibleDC(hdc);//创建兼容的内存设备对象 bg=CreateCompatibleBitmap(hdc,Border*COL,Border*ROW);//兼容位图,即是推箱子客户区的大小 SelectObject(mdc,bg);//选入位图进入内存设备对象,同时也就扩大了内存设备对象的显示表面
上图说明了如何复制的流程,观察这三个dc,尺寸是不一样的,hdc=mdc=客户区的大小,而bufdc=images的大小。
这里出现一个问题,为什么不直接把图块放在mdc中,然后再复制mdc到hdc,还要创建一个bufdc呢? 可以这样理解,实在的位图和内存块之间如何复制?至少现在知道是不行的,比如说BitBlt函数,是在内存块之间复制,不是位图和内存之间复制,所以还是建立一个bufdc,将位图放在其中,这样位图就相当于“内存块”了,于是就可以利用BitBlt位块操作,将bufdc的某个区域复制到mdc,最后将完整的mdc复制到hdc。
需要注意的几个问题
创建内存设备对象初始时只有1个像素,可以先扩大其显示表面。
第二个,观察SelectObject这个函数,假如直接将一幅存在的位图选入到某个DC中,那这个DC直接就具有了这个图像。比如:
mdc=CreateCompatibleDC(hdc); hBitmap=(HBITMAP)LoadImage(NULL,"fg.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE); SelectObject(mdc,hBitmap);
第三个,是BitBlt函数。
这个函数是位块复制函数,位块就是在内存块之间转移。从源到目的复制多大,取决于前面设置的宽和高,也就是说,源只提供坐标,从哪开始,而目的提供宽度和高度。
SelectObject和BitBlt的一点微妙关系
前面提到的,创建一个内存设备对象,初始时,是1像素,既然这么小,为什么SelectObject将一幅位图选进后,它就自动变的位图一样大呢?这个通过程序可以验证的。
按照这种思路,在创建mdc的时候,我不扩大其显示表面,被动的等待其它位块来填充,这样可行吗?验证是不行的。
这两者的对比就说明一个问题,进行SelectObject操作时,可以不指定内存设备对象的大小,直接复制。而BitBlt是位块复制,目标尺寸必须大于源的尺寸,这一点还是奇怪的。用图表示:
正是因为这个区别,在创建mdc的时候,还要多出一步,扩大其显示表面,以用于后面的复制操作!
代码表示:
hdc=GetDC(hWnd); mdc=CreateCompatibleDC(hdc); bufdc=CreateCompatibleDC(hdc);//bufdc不需要扩大,因为其用于SelectObject... bg=CreateCompatibleBitmap(hdc,Border*COL,Border*ROW); images= (HBITMAP)LoadImage(NULL,"box.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE);//直接从硬盘读取位图 SelectObject(mdc,bg);//扩大mdc的显示表面,mdc是用于复制的...
——————————————————————————————————————————————————————————————————