|

楼主 |
发表于 2005-7-22 15:10:07
|
显示全部楼层
※ LPVOID lpvObject:指向存放由调用返回的信息的缓冲区的指针。
你需要定义一个BITMAP结构类型的变量,调用GetObject()函数放入缓冲区的信息。由于BITMAP结构对我们来说是一个新的结构,所以就介绍一下:
typedef struct tagBITMAP { // bm LONG bmType; LONG bmWidth; LONG bmHeight; LONG bmWidthBytes; WORD bmPlanes; WORD bmBitsPixel; LPVOID bmBits; } BITMAP; | 很多成员,但我们实际上只对其中的两个有兴趣。但我们还是都介绍一下:
※ LONG bmType:指定位图类型,必须为0。有用吧!
※ LONG bmWidth,bmHeight:分别是位图的宽度和高度,以象素为单位。必须都大于0。
※ LONG bmWidthBytes:指定每一行扫描线中的字节数。因为Windows假定位图是字对齐的,所以这个值必须能够被2整除。
※ LONG bmPlanes:指定颜色面的数目。
※ LONG bmBitsPixel:指定表述象素颜色所需的位数。(好像没什么用)
※ LPVOID bmBits:如果你想存取实际的位图数据,这个指针指向位图位值得位置。
OK,差不多了。一旦位图被选入内存设备上下文,且代码已经得到了位图宽度和高度的必要信息后,我们就可以将内存中存储的位图通过位块传输到达屏幕,然后在任意位置对它进行显示。我说过处理位图是很容易的,对吧?(如果你觉得不容易,只能怪我说的不够好)有两个函数需要说明,先说第一个:
BOOL BitBlt( HDC hdcDest, // handle to destination device context int nXDest, // x-coordinate of destination rectangle's upper-left corner int nYDest, // y-coordinate of destination rectangle's upper-left corner int nWidth, // width of destination rectangle int nHeight, // height of destination rectangle HDC hdcSrc, // handle to source device context int nXSrc, // x-coordinate of source rectangle's upper-left corner int nYSrc, // y-coordinate of source rectangle's upper-left corner DWORD dwRop // raster operation code ); | BitBlt()函数是执行位图显示操作最简单且最直接的方法。根据函数调用的成功或失败,返回值是TRUE或FALSE。布尔函数都是这样。有很多参数,但很好理解:
※ HDC hdcDest:目标设备上下文句柄。根据我们的情况,应该是显示设备上下文句柄。
※ int nXDest,nYDest:目标矩形左上角的x、y坐标,也就是被显示的位图左上角的屏幕位置。
※ int nWidth,nHeight:位图的宽度和高度。
※ HDC hdcSrc:原来的设备上下文句柄。根据我们的情况,应该是内存设备上下文句柄。
※ int nXSrc,nYSrc:源位图的x、y坐标。由于进行位块传输的矩形必须与在参数nWidth和参数nHeight中定义的尺寸相同,所以通常都设为0。但不一定总是这样,例如你只想显示位图的一部分,就不能都设置为0。
※ DWORD dwRop:有很多光栅代码你可以选择,但只有一个我们感兴趣,SRCCOPY。它直接把源DC内的内容拷贝到目标DC中。 以上就是第一个函数。下面说说第二个函数StretchBlt(),简单的说,位图实际的拉伸或压缩就是通过它来实现的。函数的一般形式如下:
BOOL StretchBlt( HDC hdcDest, // handle to destination device context int nXOriginDest, // x-coordinate of upper-left corner of dest. rectangle int nYOriginDest, // y-coordinate of upper-left corner of dest. rectangle int nWidthDest, // width of destination rectangle int nHeightDest, // height of destination rectangle HDC hdcSrc, // handle to source device context int nXOriginSrc, // x-coordinate of upper-left corner of source rectangle int nYOriginSrc, // y-coordinate of upper-left corner of source rectangle int nWidthSrc, // width of source rectangle int nHeightSrc, // height of source rectangle DWORD dwRop // raster operation code ); | 它比BitBlt()复杂一些,所以它比BitBlt()慢。它们的参数差不多,并且有了注释,这里就不再重复了。光栅代码也是选择SRCCOPY。现在,只剩下最后一件事情——清除。建立一个设备上下文【CreateCompatibleDC(HDC hdc)】不同于得到设备上下文【(GetDC)】,不能用ReleaseDC(),要用:
参数是建立的DC的句柄。返回值是一个布尔类型,你知道布尔类型是怎么回事,对吧?All right,感觉还不坏吧。下面我们把以上步骤合并,隆重推出一个超级大包子(我觉得它有点象包子)。我事先假设你已经定义了一个全局的应用程序实例的句柄hinstance。
int ShowBitmapResource(HDC hDestDC, int xDest, int yDest, int nResID) { HDC hSrcDC; // source DC - memory device context HBITMAP hbitmap; // handle to the bitmap resource BITMAP bmp; // structure for bitmap info int nHeight, nWidth; // bitmap dimensions
// first load the bitmap resource if ((hbitmap = (HBITMAP)LoadImage(hinstance, MAKEINTRESOURCE(nResID), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION)) == NULL) return(FALSE);
// create a DC for the bitmap to use if ((hSrcDC = CreateCompatibleDC(NULL)) == NULL) return(FALSE);
// select the bitmap into the DC if (SelectObject(hSrcDC, hbitmap) == NULL) return(FALSE);
// get image dimensions if (GetObject(hbitmap, sizeof(BITMAP), &bmp) == 0) return(FALSE);
nWidth = bmp.bmWidth; nHeight = bmp.bmHeight;
// copy image from one DC to the other if (BitBlt(hDestDC, xDest, yDest, nWidth, nHeight, hSrcDC, 0, 0, SRCCOPY) == NULL) return(FALSE);
// kill the memory DC DeleteDC(hSrcDC);
// return success! return(TRUE); } | ☆ 最后一件事
你可能还不太明白,但你现在确实有足够的知识用Windows GDI在窗口里建立一个小游戏了!你能创建窗口,显示图形。游戏的逻辑同DOS下的C语言游戏逻辑一样,即使你不知道DOS下的C,你玩过游戏吧,玩过就应该有个初步的认识。你甚至能用鼠标处理产生的消息。但有一件事儿我们漏了,可能它不属于本章的范围,但我们不能不提它——键盘支持。Windows提供了一个非常好的函数GetAsyncKeyState()检测键盘的状态。它返回一个16位的值,高字节显示了一个键子是否被按下。它的原形如下: SHORT GetAsyncKeyState(int vKey);
参数是键子的标识符。都以VK_开头,例如一些最常用的:VK_RETURN,VK_ESCAPE,VK_UP,VK_LEFT,VK_RIGHT和VK_DOWN。你甚至可以用VK_LBUTTON和VK_RBUTTON标识鼠标按键。多方便呀。观察高字节,如果是1,键子就是正被按下。我总是用一个宏来做这些:
#define KEYSTATE(vknum) ((GetAsyncKeyState(vknum) & 0x8000) ? TRUE : FALSE) | 如果你不仔细,可能还没有注意到这个条件符号(?),在C语言中是一个三元算子——评估它左边的表达式。如果表达式的值为true,表达式就是冒号左边的值,如果false,就是冒号右边的值。明白了吗?好极了!
☆ 总结
现在,你可以做GDI基础的游戏了。本章比我原打算的要长一些。由于讲的内容较多,我做了一个例程给你借鉴。它是类似于屏幕保护的东东,只生成一个.EXE文件格式,不是全屏的,在一个小窗口里。它展示了出口的创建和相应了几个键盘消息…………。
|
|