第四章 输出文本
客户区是整个应用程序窗口中未被标题栏、窗口边框以及可选的菜单栏、工具栏、状态栏和滚动条占据的部分。简而言之,客户区是窗口中可以由程序任意书写和传递可视信息的部分。
<1> WM_PAINT消息
在发生下面几种事件之一时,窗口过程会接收到一个WM_PAINT消息:
1.在用户移动窗口或显示窗口时,窗口中先前被隐藏的区域重新可见;
2.用户改变窗口的大小;
3.程序使用ScrollWindow或ScrollDC函数滚动客户区的一部分;
4.程序使用InvalidateRect或InvalidateRgn函数显示产生WM_PAINT消息。
下面的情况下,Windows可能发送WM_PAINT消息:
1.Windows擦除覆盖了部分窗口的对话框或消息框;
2.菜单下拉出来,然后被释放;
3.显示工具提示。
在下面情况下,Windows总是保存它所覆盖的显示区域,然后恢复它:
1.鼠标光标穿越客户区;
2.图标拖过客户区。
<2> 有效矩形和无效矩形
在擦除对话框之后,需要重画的只是先前被对话框遮住的矩形区域。这个区域称为"无效区域"或"更新区域"。正是客户区内无效区域的存在,才提示Windows将一个WM_PAINT消息放在应用程序的消息队列中。只有在客户区的某一部分失效时,窗口才会接收WM_PAINT消息。
Windows内部为每个窗口保存一个"绘图信息结构",这个结构包含了包围无效区域的最小矩形的坐标以及其他信息。窗口过程可以通过调用InvalidateRect使客户区内的矩形无效。如果消息队列中已经包含一个WM_PAINT消息,Windows将计算出新的无效矩形;否则,它将一个新的WM_PAINT消息放入消息队列中。在接收到WM_PAINT消息时,窗口过程可以获取无效矩形的坐标。通过调用GetUpdateRect,可以在任何时候获取这些坐标。
在处理WM_PAINT消息期间,窗口过程在调用了BeginPaint之后,整个客户区即变为有效。程序也可以通过调用ValidateRect函数使客户区内任意矩形区域变为有效。
<3> 设备描述表
当程序需要绘图时,它必须先获取设备描述表结构。在获取了该句柄后,Windows用默认的属性值填充内部设备描述表结构。当程序在客户区绘图完毕后,它必须释放设备描述表句柄。
Windows应用程序可使用两种方法来获得设备描述表句柄,以备在屏幕上绘图。
方法一:
case WM_PAINT:
hdc=BeginPaint(hwnd,&ps);
Endpaint(hwnd,&ps);
return 0; //仅仅使先前无效区域变为有效
case WM_PAINT:
return 0; //错误,Windows不会使该区域变为有效,相反,windows会将WM_PAINT消息一直发送下去。
要在处理WM_PAINT消息时在更新的矩形外绘图,可以在调用BeginPaint之前使用如下调用:InvalidateRect(hwnd,NULL,TRUE);它使整个客户区变为无效,并擦除背景,但若最后一个参数为FALSE,则不擦除背景,原有的东西将保留在原处。
方法二:
hdc=GetDC(hwnd);
[use GDI functions]
ReleaseDC(hwnd,hdc);
GetDC和ReleaseDC也必须成对使用。与从BeginPaint返回设备描述表句柄不同,GetDC返回的设备描述表句柄具有一个剪裁矩形,它等于整个客户区。与BeginPaint不同,GetDC不会使任何无效区域变为有效。如果需要使整个客户区有效,可以调用ValidateRect(hwnd,NULL);一般可以调用GetDC和ReleaseDC来对键盘消息或鼠标消息做出反应。
GetDC返回用于写入窗口客户区的设备描述表句柄,而GetWindowDC返回写入整个窗口的设备描述表句柄。例如,您的程序可以使用从GetWindowDC返回的设备描述表句柄在窗口的标题栏上写入文字。
如TextOut函数中,传递给函数的坐标常常被称为"逻辑坐标"。Windows有多种不同的"映射方式",它们用来控制GDI绘图函数指定的逻辑坐标转换为显示器的物理像素坐标的方式。映射方式在设备描述表中定义,默认的映射方式是MM_TEXT,也就是说,逻辑单位与设备单位相同,都是相对于客户区左上角的像素数;x的值从左向右递增,y的值从上往下递增。
<4> 系统字体
要用TextOut显示多行文本,就必须确定字体的字符大小。
程序可以调用GetSystemMetrics函数来确定关于用户界面构件大小的信息,调用GetTextMetrics来确定字体大小。用下述方式调用
GetTextMetrics:
TEXTMETRIC tm;
hdc=GetDC(hwnd);
GetTextMetrics(hdc,&tm);
ReleaseDC(hwnd,hdc);
平均字符宽度cxChar=tm.tmAveCharWidth;
总的字符高度cyChar=tm.tmHeight+tm.tmExternalLeading;
大写字母的平均宽度cxCaps=(tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar/2;
获得客户区大小的方法:
case WM_SIZE:
cxClient=LOWORD(lParam);
cyClient=HIWORD(lParam);
return 0;
<5> 滚动条
SetScrollRange设置滚动范围;
SetScrollPos在滚动条范围内设置新的滚动框位置;
GetScrollRange和GetScrollPos获取当前范围和位置。
在用鼠标单击或拖动滚动条时,Windows给窗口过程发送WM_VSCROLL和WM_HSCROLL消息。对于这两个消息,wParam消息参数的低字节指出了鼠标对滚动条进行的操作,被看做一个"通知码"。通知码的值由以SB开头的标识符定义。
Win32 API介绍的两个滚动条函数称作SetScrollInfo和GetScrollInfo,这些函数完成以前函数的全部功能,并增加了两个新特性。第一个功能涉及滚动条的大小,第二个是通过GetScrollInfo可以获取真实的32位值。