如果使用过现有的Windows应用程序,可能会发现窗口的尺寸变化极大。窗口最大化时(假定窗口只有标题栏并且没有菜单),客户区几乎占据了整个屏幕。这一最大化了的客户区的尺寸可以通过以SM_CXFULLSCREEN和SM_CYFULLSCREEN为参数调用GetSystemMetrics来获得。窗口的最小尺寸可以很小,有时甚至不存在,更不用说客户区了。
当然我们可以使用GetClientRect函数来确定客户区的大小。使用这个函数没有什么错,但是在每次使用信息时调用它是没有效率的。确定窗口客户区大小的更好方法是在窗口过程中处理WM_SIZE消息。在窗口大小改变时,Windows给窗口过程发送一个WM_SIZE消息。传给窗口过程的lParam参数的低位字中包含客户区的宽度,高位字中包含客户区的高度。要保存这些尺寸,需要在窗口过程中定义两个静态变量:
static int cxClient,cyClient;
这两个变量在窗口过程内定义为静态变量,因为在以后处理其他消息时会用到它们。处理WM_SIZE的方法如下:
case WM_SIZE:
cxClient=LOWORD(lParam);
cyClient=HOWORD(lParam);
return 0;
实际上我们会在每个Windows程序中看到类似的代码。LOWORD和HOWORD宏在Windows头文件WINDEF.H中定义。这些类似的宏的定义看如下:
#define MAKEWORD(a, b) ((WORD)(((BYTE)(a)) | ((WORD)((BYTE)(b))) << 8))
#define MAKELONG(a, b) ((LONG)(((WORD)(a)) | ((DWORD)((WORD)(b))) << 16))
#define LOWORD(l) ((WORD)(l))
#define HIWORD(l) ((WORD)(((DWORD)(l) >> 16) & 0xFFFF))
#define LOBYTE(w) ((BYTE)(w))
#define HIBYTE(w) ((BYTE)(((WORD)(w) >> 8) & 0xFF))
这两个宏返回WORD值(16位的无符号整数,范围从0到0xFFF)。一般,将这些值保存在32位带符号整数中。这就不会牵到任何转换问题,并使得这些值在以后需要的任何计算中易于使用。
在许多Windows程序中,WM_SIZE消息必然跟着一个WM_PAINT消息。为什么呢?
因为在我们定义窗口类时指定类风格为CS_HREDRAW|CS_VREDRAW
这种类风格告诉Windows,如果水平或者垂直大小发生改变,则强行刷新客户区。
用如右公式计算可以在客户区内显示的文本的总行数:cyClient/cyChar; //cyChar为总的字符高度,通过GetTextMetrics调用来获得(这里不在说明)
如果客户区的高度太小以至于无法显示一个完整的字符,这个公式的结果可以为0。类似地,在客户区的水平方向可以显示的小写字符的近似数目为 cxClient/cxChar; //这里的cxChar是平均字符宽度
如果在处理WM_CREATE消息期间确定cxChar和cyChar,则不用担心在这两个计算公式中会出现被0除的情况。在WinMain调用CreateWindows时,窗口过程接收一个WM_CREATE消息。在WinMain调用ShowWindows之后接收到第一个WM_CREATE消息,此时cxChar和cyChar已经被赋予正的非零值了。
如果客户区的大小不足以容纳所有的内容,那么,知道窗口客户区的大小只是为用户提供了在客户区内移动文本的第一步。如果您对其他有类似需求的Windows应用程序很熟悉,就很可能知道,这种情况下,我们需要使用“滚动条”。