本文是我学习《windows程序设计》(第5版)的笔记,方便以后查阅。如果被您看到并且对您有用的话,那再好不过了。本文不涉及具体的讲解,详细的讲解请看《windows程序设计》(第5版)这本书,它才是经典之作!
为了在窗口客户区输出文本,本章用到的一个主要函数是TextOut()函数。
函数原型
BOOL TextOut(
HDC hdc, // 设备环境句柄
int nXStart, // 字符串的开始位置 x坐标
int nYStart, // 字符串的开始位置 y坐标
LPCTSTR lpString, // 字符串
int cbString // 字符串中字符的个数
);
设备环境句柄:设备环境句柄是程序窗口使用GDI函数的“通行证”,有了设备环境句柄你就可以随心所欲绘制你的客户区了。当你获得的设备环境句柄不再有用时应当将其释放,因此得到设备环境句柄的函数与释放设备环境句柄的函数总是成对出现在同一个消息处理过程之中的。
获取设备环境句柄的两种方法:
方法一:
这种方法可以在处理WM_PAINT消息时使用。使用BeginPaint函数,该函数返回设备环境的句柄,而函数EndPaint函数使用来释放改句柄的,一般代码是:
CASE WM_PAINT:
hDC = BeginPaint(hwnd,&ps);
【use GDI function】
EndPaint(hwnd,&ps);
return 0;
其中BeginPaint的第一个参数为:窗口句柄,另一个为:PAINTSTRUCT(绘图信息结构体)结构变量的地址,其具体定义为:
typedef struct tagPAINTSTRUCT
{
HDC hdc;
BOOL fErase;
RECT rcPaint;
BOOL fRestore;
BOOL flncUpdate;
BYTE rgbReserved[32];
}PAINTSTRUCT;
在程序调用BeiginPaint时,windows填充该结构体的各个字段。用户程序只是使用了该结构体的前三个字段,第一个字段为:设备环境句柄,第二个字段为:标识了windows是否已经擦出了无效区域的背景,当该字段为false是那么就表示windows已经擦出了无效矩形区域的背景,如果为true,那么就表示windows没有将无效区域的背景擦出,换句话说就是:无效区域中的画面是什么,现在还是什么,没有改变。第三个字段为一个rect结构体,其表示出了无效区域的范围,也就是要重绘的无效区域。
如果你要在无效区域之外绘图,那么你就应该在BeginPaint函数调用以前,用函数InvalidateRect使整个客户区无效并擦出背景。
方法二:
在程序中并不是总是在WM_PAINT中重绘无效区域,那么就不能使用BeginPaint与EndPaint的函数组合了,因为他们只能用于处理WM_PAINT消息中使用,那么在别的地方可以使用GetDC函数了获得设备环境句柄,而用ReleaseDC函数释放。GetDC函数与ReleaseDC函数必须成对出现。
另:与GetDC函数类似的是GetWindowDC函数, GetDC函数返回的是窗口客户区的设备环境句柄,GetWindowDC函数返回的是整个窗口的设备环境句柄。
实例程序中还用到一下两个函数:
GetTextMetrics:该函数把程序当前的字体信息,存放到TEXTMETRIC结构中,共有20个字体信息,本程序中用到了3个,分别是
tmAveCharWidth(小写字符的加权平均宽度),
tmHeight(字符高度)
tmExternalLeading(外部间距),
GetSystemMetrics:用于得到被定义的系统数据或者系统配置信息,可以获取系统分辨率,但这只是其功能之一,GetSystemMetrics函数只有一个参数,称之为「索引」,这个索引有75个标示符,通过设置不同的标识符就可以获取系统分辨率、窗体显示区域的宽度和高度、滚动条的宽度和高度等。本程序在头文件SysText.h中定义了一个结构体数组sysmetrics[],数组长度正好是75,第一个变量就是这75个索引的标示符。
下面请看头文件SysText.h。
/*----------------------------------------------- SYSMETS.H -- System metrics display structure -----------------------------------------------*/ #define NUMLINES ((int) (sizeof sysmetrics / sizeof sysmetrics [0]))//显示行数,75行 struct { int iIndex ; TCHAR * szLabel ; TCHAR * szDesc ; } sysmetrics [] = { SM_CXSCREEN, TEXT ("SM_CXSCREEN"), TEXT ("Screen width in pixels"), SM_CYSCREEN, TEXT ("SM_CYSCREEN"), TEXT ("Screen height in pixels"), SM_CXVSCROLL, TEXT ("SM_CXVSCROLL"), TEXT ("Vertical scroll width"), SM_CYHSCROLL, TEXT ("SM_CYHSCROLL"), TEXT ("Horizontal scroll height"), SM_CYCAPTION, TEXT ("SM_CYCAPTION"), TEXT ("Caption bar height"), SM_CXBORDER, TEXT ("SM_CXBORDER"), TEXT ("Window border width"), SM_CYBORDER, TEXT ("SM_CYBORDER"), TEXT ("Window border height"), SM_CXFIXEDFRAME, TEXT ("SM_CXFIXEDFRAME"), TEXT ("Dialog window frame width"), SM_CYFIXEDFRAME, TEXT ("SM_CYFIXEDFRAME"), TEXT ("Dialog window frame height"), SM_CYVTHUMB, TEXT ("SM_CYVTHUMB"), TEXT ("Vertical scroll thumb height"), SM_CXHTHUMB, TEXT ("SM_CXHTHUMB"), TEXT ("Horizontal scroll thumb width"), SM_CXICON, TEXT ("SM_CXICON"), TEXT ("Icon width"), SM_CYICON, TEXT ("SM_CYICON"), TEXT ("Icon height"), SM_CXCURSOR, TEXT ("SM_CXCURSOR"), TEXT ("Cursor width"), SM_CYCURSOR, TEXT ("SM_CYCURSOR"), TEXT ("Cursor height"), SM_CYMENU, TEXT ("SM_CYMENU"), TEXT ("Menu bar height"), SM_CXFULLSCREEN, TEXT ("SM_CXFULLSCREEN"), TEXT ("Full screen client area width"), SM_CYFULLSCREEN, TEXT ("SM_CYFULLSCREEN"), TEXT ("Full screen client area height"), SM_CYKANJIWINDOW, TEXT ("SM_CYKANJIWINDOW"), TEXT ("Kanji window height"), SM_MOUSEPRESENT, TEXT ("SM_MOUSEPRESENT"), TEXT ("Mouse present flag"), SM_CYVSCROLL, TEXT ("SM_CYVSCROLL"), TEXT ("Vertical scroll arrow height"), SM_CXHSCROLL, TEXT ("SM_CXHSCROLL"), TEXT ("Horizontal scroll arrow width"), SM_DEBUG, TEXT ("SM_DEBUG"), TEXT ("Debug version flag"), SM_SWAPBUTTON, TEXT ("SM_SWAPBUTTON"), TEXT ("Mouse buttons swapped flag"), SM_CXMIN, TEXT ("SM_CXMIN"), TEXT ("Minimum window width"), SM_CYMIN, TEXT ("SM_CYMIN"), TEXT ("Minimum window height"), SM_CXSIZE, TEXT ("SM_CXSIZE"), TEXT ("Min/Max/Close button width"), SM_CYSIZE, TEXT ("SM_CYSIZE"), TEXT ("Min/Max/Close button height"), SM_CXSIZEFRAME, TEXT ("SM_CXSIZEFRAME"), TEXT ("Window sizing frame width"), SM_CYSIZEFRAME, TEXT ("SM_CYSIZEFRAME"), TEXT ("Window sizing frame height"), SM_CXMINTRACK, TEXT ("SM_CXMINTRACK"), TEXT ("Minimum window tracking width"), SM_CYMINTRACK, TEXT ("SM_CYMINTRACK"), TEXT ("Minimum window tracking height"), SM_CXDOUBLECLK, TEXT ("SM_CXDOUBLECLK"), TEXT ("Double click x tolerance"), SM_CYDOUBLECLK, TEXT ("SM_CYDOUBLECLK"), TEXT ("Double click y tolerance"), SM_CXICONSPACING, TEXT ("SM_CXICONSPACING"), TEXT ("Horizontal icon spacing"), SM_CYICONSPACING, TEXT ("SM_CYICONSPACING"), TEXT ("Vertical icon spacing"), SM_MENUDROPALIGNMENT, TEXT ("SM_MENUDROPALIGNMENT"), TEXT ("Left or right menu drop"), SM_PENWINDOWS, TEXT ("SM_PENWINDOWS"), TEXT ("Pen extensions installed"), SM_DBCSENABLED, TEXT ("SM_DBCSENABLED"), TEXT ("Double-Byte Char Set enabled"), SM_CMOUSEBUTTONS, TEXT ("SM_CMOUSEBUTTONS"), TEXT ("Number of mouse buttons"), SM_SECURE, TEXT ("SM_SECURE"), TEXT ("Security present flag"), SM_CXEDGE, TEXT ("SM_CXEDGE"), TEXT ("3-D border width"), SM_CYEDGE, TEXT ("SM_CYEDGE"), TEXT ("3-D border height"), SM_CXMINSPACING, TEXT ("SM_CXMINSPACING"), TEXT ("Minimized window spacing width"), SM_CYMINSPACING, TEXT ("SM_CYMINSPACING"), TEXT ("Minimized window spacing height"), SM_CXSMICON, TEXT ("SM_CXSMICON"), TEXT ("Small icon width"), SM_CYSMICON, TEXT ("SM_CYSMICON"), TEXT ("Small icon height"), SM_CYSMCAPTION, TEXT ("SM_CYSMCAPTION"), TEXT ("Small caption height"), SM_CXSMSIZE, TEXT ("SM_CXSMSIZE"), TEXT ("Small caption button width"), SM_CYSMSIZE, TEXT ("SM_CYSMSIZE"), TEXT ("Small caption button height"), SM_CXMENUSIZE, TEXT ("SM_CXMENUSIZE"), TEXT ("Menu bar button width"), SM_CYMENUSIZE, TEXT ("SM_CYMENUSIZE"), TEXT ("Menu bar button height"), SM_ARRANGE, TEXT ("SM_ARRANGE"), TEXT ("How minimized windows arranged"), SM_CXMINIMIZED, TEXT ("SM_CXMINIMIZED"), TEXT ("Minimized window width"), SM_CYMINIMIZED, TEXT ("SM_CYMINIMIZED"), TEXT ("Minimized window height"), SM_CXMAXTRACK, TEXT ("SM_CXMAXTRACK"), TEXT ("Maximum draggable width"), SM_CYMAXTRACK, TEXT ("SM_CYMAXTRACK"), TEXT ("Maximum draggable height"), SM_CXMAXIMIZED, TEXT ("SM_CXMAXIMIZED"), TEXT ("Width of maximized window"), SM_CYMAXIMIZED, TEXT ("SM_CYMAXIMIZED"), TEXT ("Height of maximized window"), SM_NETWORK, TEXT ("SM_NETWORK"), TEXT ("Network present flag"), SM_CLEANBOOT, TEXT ("SM_CLEANBOOT"), TEXT ("How system was booted"), SM_CXDRAG, TEXT ("SM_CXDRAG"), TEXT ("Avoid drag x tolerance"), SM_CYDRAG, TEXT ("SM_CYDRAG"), TEXT ("Avoid drag y tolerance"), SM_SHOWSOUNDS, TEXT ("SM_SHOWSOUNDS"), TEXT ("Present sounds visually"), SM_CXMENUCHECK, TEXT ("SM_CXMENUCHECK"), TEXT ("Menu check-mark width"), SM_CYMENUCHECK, TEXT ("SM_CYMENUCHECK"), TEXT ("Menu check-mark height"), SM_SLOWMACHINE, TEXT ("SM_SLOWMACHINE"), TEXT ("Slow processor flag"), SM_MIDEASTENABLED, TEXT ("SM_MIDEASTENABLED"), TEXT ("Hebrew and Arabic enabled flag"), SM_MOUSEWHEELPRESENT, TEXT ("SM_MOUSEWHEELPRESENT"), TEXT ("Mouse wheel present flag"), SM_XVIRTUALSCREEN, TEXT ("SM_XVIRTUALSCREEN"), TEXT ("Virtual screen x origin"), SM_YVIRTUALSCREEN, TEXT ("SM_YVIRTUALSCREEN"), TEXT ("Virtual screen y origin"), SM_CXVIRTUALSCREEN, TEXT ("SM_CXVIRTUALSCREEN"), TEXT ("Virtual screen width"), SM_CYVIRTUALSCREEN, TEXT ("SM_CYVIRTUALSCREEN"), TEXT ("Virtual screen height"), SM_CMONITORS, TEXT ("SM_CMONITORS"), TEXT ("Number of monitors"), SM_SAMEDISPLAYFORMAT, TEXT ("SM_SAMEDISPLAYFORMAT"), TEXT ("Same color format flag") } ;
第四章的第一个实例程序就是用TextOut()函数在窗口客户区输出运行改程序的电脑的系统配置信息。
注释版主程序如下:
#include <windows.h> #include "SysText.h" LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT ("SysMats1") ; HWND hwnd ; MSG msg ; WNDCLASS wndclass ; wndclass.style = CS_HREDRAW | CS_VREDRAW ;//类风格 wndclass.lpfnWndProc = WndProc ;//设定窗口类的窗口过程 wndclass.cbClsExtra = 0 ;//预留额外空间 wndclass.cbWndExtra = 0 ;//预留额外空间 wndclass.hInstance = hInstance ;//实例句柄 wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;//加载光标 wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;//加载鼠标光标 wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;//获取一个图形对象 wndclass.lpszMenuName = NULL ;//指定窗口类菜单 wndclass.lpszClassName = szAppName ;//赋给窗口类一个名称 if (!RegisterClass (&wndclass))//注册窗口类 return -1 ; hwnd = CreateWindow (szAppName, // 窗口类名称 TEXT ("Get System Metrics No. 1"), // 窗口标题 WS_OVERLAPPEDWINDOW, // 窗口风格 CW_USEDEFAULT, // 初始X坐标 CW_USEDEFAULT, // 初始Y坐标 CW_USEDEFAULT, // 初始X方向尺寸 CW_USEDEFAULT, // 初始Y方向尺寸 NULL, // 父窗口句柄 NULL, // 窗口菜单句柄 hInstance, // 程序实例句柄 NULL) ; // 创建参数 ShowWindow (hwnd, iCmdShow) ;//显示窗口 UpdateWindow (hwnd) ;//指示窗口对自身进行重绘 while (GetMessage (&msg, NULL, 0, 0))//从消息队列获取消息 { TranslateMessage (&msg) ;//翻译一些键盘消息 DispatchMessage (&msg) ;//将消息发送给窗口过程 } return msg.wParam ; } //窗口过程 LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc ; PAINTSTRUCT ps ; RECT rect ; static int cxChar, cxCaps, cyChar ;//定义字体宽度,大写字符的平均宽度,高度变量 int i ; TCHAR szBuffer [10] ;//定义缓冲区 TEXTMETRIC tm ;//定义TEXTMETRIC结构体,为了保存字体信息 switch (message) { case WM_CREATE: hdc = GetDC (hwnd) ;//获得设备环境句柄 GetTextMetrics (hdc, &tm) ;//将字体信息保存到TEXTMETRIC结构体tm中 cxChar = tm.tmAveCharWidth ;//字体宽度=小写字符的加权平均宽度 cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2 ;//大写字符的平均宽度 cyChar = tm.tmHeight + tm.tmExternalLeading ;//字体高度=字符高度+外部间距(两行文本之间的间距) ReleaseDC (hwnd, hdc) ;//释放设备环境句柄 return 0 ; case WM_PAINT: hdc = BeginPaint (hwnd, &ps) ;//表明窗口绘制开始 for (i = 0 ; i < NUMLINES ; i++) { TextOut (hdc, 0, cyChar * i, sysmetrics[i].szLabel, lstrlen (sysmetrics[i].szLabel)) ;//从每行的最左边显示 TextOut (hdc, 22 * cxCaps, cyChar * i, sysmetrics[i].szDesc, lstrlen (sysmetrics[i].szDesc)) ;//从每行的22个大写字符宽度处显示 SetTextAlign (hdc, TA_RIGHT | TA_TOP) ;//设置文字对齐标志,下面的TextOut函数使用的坐标将从 //客户区右上角开始计算,而不是默认的左上角 TextOut (hdc, 22 * cxCaps + 40 * cxChar, cyChar * i, szBuffer, wsprintf (szBuffer, TEXT ("%5d"), GetSystemMetrics (sysmetrics[i].iIndex))) ;//得到每个索引的系统配置信息,并输出 SetTextAlign (hdc, TA_LEFT | TA_TOP) ;//设置文字对齐标志,从客户区左上角 } EndPaint (hwnd, &ps) ;//窗口绘制结束 return 0 ; case WM_DESTROY: PostQuitMessage (0) ;//将“退出”消息插入消息队列 return 0 ; } return DefWindowProc (hwnd, message, wParam, lParam) ;//执行默认的消息处理 }
程序中有这么一行代码:cxCaps=(tm.tmPitchAndFamily&1?3:2)*cxChar/2;
在等宽字体中,cxCaps=cxChar,在变宽字体中cxCaps=1.5*cxChar,在结构体中tmPitchAndFamily字段的低位决定字体是否为等宽字体,1代表变宽字体,0代表等宽字体。所以程序利用这行代码计算cxCaps。
这个程序的不足之处是,除非你电脑的显示屏足够大,不然这75行文字是无法完全显示在你的屏幕上的,所以接下来的实例作者介绍了滚动条的使用方法。