第四章 输出文本
需要非常清楚一个概念----窗口的客户区(Client Area):整个应用程序窗口中未被标题栏,窗口边框以及可选的菜单栏,工具栏,状态栏和滚动条占据的部分。
在Windows中,我们能在窗口的客户区绘制文本和图形,而当窗口的客户区被变动时,Windows不能保留原来绘制的文本和图形,如果要恢复原来的文本和图形就必须进行重新绘制,这个过程叫刷新。如果当Windows向窗口过程发送WM_PAINT消息,窗口的客户区就需要‘刷新’。
Windows什么时候向窗口过程发送WM_PAINT消息,或者说什么时候窗口的客户区被变动呢?主要是一下几种情况:
1) 在用户移动窗口或显示窗口时,窗口中先前隐藏的区域重新可见;
2) 用户改变窗口的大小。
3) 程序使用ScrollWindow或ScrollDC函数滚动客户区的一部分;
4) 程序使用InvalidateRect或InvalidateRgn函数显式产生WM_PAINT消息
5) 覆盖了部分窗口的对话框或消息框被移开;
6) 菜单下拉出来,然后被释放;
7) 显示工具提示;
8) 鼠标光标在客户区移动;
9) 图标在客户区中托动。
上面的各种情况实际上都是使窗口客户区的全部或一部分原有的文本和图形信息被‘覆盖’,变为‘无效’的窗口客户区,当窗口客户区的全部或一部分‘无效’时,Windows就向窗口过程发送WM_PAINT消息,是窗口‘有效’,再重新绘制窗口。
在窗口的客户区绘制,要使用Windows的图形设备接口(GDI)函数,上一章用到的DrawText就是一个GDI函数,它可以在窗口中绘制相应的一行文字。几乎每个图形设备接口函数都需要设备环境(DC:Device Context)句柄作为参数,DC是一个保存绘制时所需各种属性(比如文本字体,文本颜色,线的粗细等)的数据结构,我们可以用一些GDI函数改变这些属性。
我们只有获得DC的句柄才能在屏幕上绘制文字或图形。获得DC句柄的方法有两个。
一种是在处理WM_PAINT消息时(出现无效矩形(窗口)的情况),使用BeginPaint和EndPaint两个函数:
case WM_PAINT:
HCD hdc;//定义一个DC句柄变量
PAINTSTRUCT ps;
hdc = BeginPaint(hwnd, &ps);使无效窗口变为有效,并获得一个DC句柄
[使用 GDI 函数 ]
EndPaint(hwnd, &ps); 释放DC句柄
在处理WM_PAINT消息必须按上面的方法进行,否则程序将出错!这是因为BeginPaint函数是窗口‘有效’,然后可以绘制窗口。如果没有BeginPaint函数,则窗口还是‘无效’的,Windows将不断向窗口过程发送WM_PAINT消息,有可能造成系统崩溃!
另一种方法可以随时获得一个DC句柄:
DHC hdc;
hdc = GetDC(hwnd); 获得一个DC句柄
[使用GDI函数]
ReleaseDC(hwnd, hdc); 释放DC句柄
现在我们就可以用GDI函数在窗口的客户区绘制文本或图形了,本章举了一个例子:输出文本。
书中的例子运用GetSystemMetrics函数取得用户界面构件大小的信息(比如:屏幕宽度和高度,窗口中标题栏的高度等),并用TextOut这个GDI函数把这些信息按行显示在窗口的客户区中。书中通过三个步骤逐渐的把这个程序的功能扩充加强,最后得到一个比较完美而有意义的程序。这个过程在我们的实际工作中是非常有用的,开发一个软件可以先实现软件的主要功能,然后再根据需要把这个软件的功能逐步扩充,同时也是我们的编程知识和能力不断增加的过程。
滚动条(Scroll Bars)是图形用户界面最好的功能之一,当显示的文本,图形等所需的空间超出了窗口的客户区所能提供的空间,就可以使用滚动条。在应用程序中包含水平或垂直滚动条,只需在CreateWindow函数的第三个参数中包含窗口风格WS_VSCROLL(垂直)或WS_HSCROLL(水平)即可。用鼠标单击滚动条或托动滚动小块时,Windows向窗口过程发送WM_VSCROLL和WM_HSCROLL消息,在消息参数wParam中的低16位字节中保存指示鼠标操作的“通知码”(Notification Code)。通过通知码,我们就可以对鼠标的各种操作进行相应的处理。
....
case WM_VSCROLL:
switch(LOWORD(wParam)) 取得wParam中的低16位字节的值
{
case SB_LINEUP: “通知码”通知我们鼠标让滚动条向上滚动一行
... 相应的处理
case SB_LINEDOWN: “通知码”通知我们鼠标让滚动条向下滚动一行
... 相应的处理
}
return 0;
如何对滚动条进行相应的处理呢?利用SetScrollInfo,GetScrollInfo和ScrollWindow三个函数可以对滚动条进行各种处理,这些函数的意义和使用方法可以参照书中的第三个例子以及MSDN。
值得注意的是:Windows自动处理滚动条的所有鼠标操作,但不处理键盘的操作,这就需要加入相应的代码来支持键盘的操作,在下一章会学到。