本节我们将讲述如何在窗口客户区绘制文本。如果在客户区绘制文本,需要将整个客户区或指定文本所在的矩形区域设置为无效区域,然后产生WM_PANIT消息,调用GDI函数绘制文本。此外,如果要绘制文本还需要使用设备环境上下文句柄,涉及到绘制文本的字体、字符的大小和文本尺寸以及文本的格式化。
本节必须掌握的知识点:
无效矩形与有效矩形
设备环境
字体与字符
第19练:获取系统配置信息No.1
3.1.1 无效矩形与有效矩形
■窗口客户区
如图3-1所示。
图3-1 窗口客户区
窗口客户区为窗口标题栏以下的部分。用户可以通常通过拖动窗口改变窗口的大小,同时也改变了窗口客户区的大小。Windows程序可以在窗口客户区绘制并传达可视化信息的区域。
■WM_PAINT消息
大多数Windows程序在WinMain函数初始化过程中会在进入消息循环之前调用UpdataWindow函数。Windows利用这个机会向窗口过程发送最初的WM_PAINT消息。通知窗口过程绘制客户区。此后,窗口过程需要在几乎任何时间都能够处理新的WM_PAINT消息,而且在必要时重绘整个客户区。在以下任何一个事件发生时窗口过程都会收到一条WM_PAINT消息:
•用户移动一个窗口,导致原来被遮盖的部分窗口暴露出来。
•用户调整窗口的大小(当窗口的类似设定为CS_HREADRAM和CS_VREADRAM值时)。
•程序调用ScrollWindow或ScrollDC函数滚动客户区。
•程序调用InvalidateRect或InvalidateRgn函数显示生成WM_PAINT消息。
在某些情况下,当客户区的一部分被临时覆盖时,Windows会试图保存被覆盖的部分,以便将来恢复时使用。这并不是每次都能成功。在以下情形,Windows有时会发送一条WM_PAINT消息:
•windows关闭了一个覆盖了部分窗口的对话框或消息框。
•下拉菜单被拉下然后收回。
•显示提示信息。
在少数情况下,Windows总是会保存被覆盖部分的显示内容,然后再恢复。这些情况如下:
•鼠标指针在客户区内移动。
•在客户区内拖动图标。
处理WM_PAINT消息需要我们改变对于视频输出的概念。程序应该收集并保存所有用于绘制客户区的信息,但是只在需要时才会进行绘制——当收到WM_PAINT消息时,如果程序需要在其他时候更新客户区,可以强制Windows生成WM_PAINT消息。这看上去貌似绕了一个弯,但是程序的结构会因此受益。
■有效矩形
在Windows窗口中,窗口的有效矩形区域指的是窗口中实际可以绘制内容的区域,也就是排除掉标题栏、边框和其他非客户区的区域。有效矩形区域通常用矩形的左上角和右下角坐标表示,可以由GetClientRect函数获取:
●GetClientRect:此函数用于获取窗口客户区的矩形区域坐标。该函数接受窗口句柄参数和一个指向RECT结构体的指针,将窗口客户区的矩形区域坐标存储在该结构体中。
BOOL GetClientRect(
HWND hWnd, //窗口句柄
LPRECT lpRect //RECT结构体的指针
);
示例代码:
RECT rcClient;
GetClientRect(hWnd, &rcClient);
●AdjustWindowRect:此函数用于根据指定的窗口样式和客户区矩形区域计算出整个窗口的矩形区域坐标(包含标题栏、边框等)。
BOOL AdjustWindowRect(
LPRECT lpRect, //指定的矩形区域
DWORD dwStyle, //窗口样式
BOOL bMenu //菜单
);
示例代码:
RECT rcClient = { 0, 0, clientWidth, clientHeight };
AdjustWindowRect(&rcClient, dwStyle, FALSE);
■无效矩形
在Windows系统的图形界面中,无效矩形区域(Invalid Rectangular Region)通常指的是窗口中需要重新绘制的部分。当窗口的内容发生变化,或者被其他窗口遮挡后又显现出来时,相关的区域会被标记为“无效”,并且需要在下一个画图周期(Paint cycle)中重绘。
无效区域是通过Windows的消息系统来处理的。当部分窗口变成无效时,系统会发出WM_PAINT消息,并在下一个画图周期中,调用该窗口对应的窗口过程函数来重新绘制无效区域。
如果在程序中需要手动设置无效区域,可以使用以下的一些函数:
●InvalidateRect:此函数会将窗口的整个区域或者指定的区域标记为无效,函数原型如下:
BOOL InvalidateRect(
HWND hWnd,
const RECT *lpRect,
BOOL bErase
);
hWnd:窗口句柄,指定要进行区域无效化的窗口。
lpRect:指向一个RECT结构的指针,用于指定要无效化的矩形区域。如果此参数为NULL,则整个窗口都会被标记为无效。
bErase:是否在下次画图消息处理时擦除背景。
●InvalidateRgn:与InvalidateRect类似,但是它用来设置无效的区域(Region)。
在接收到WM_PAINT消息时,可以调用BeginPaint函数来获取无效区域,并开始绘制过程,完成绘制后则调用EndPaint结束。BeginPaint在处理完消息后,会自动验证窗口(即清除无效区域标记)。
●如果消息队列中已经有一条WM_PAINT消息,Windows会重新计算一个新的无效矩形。否则windows会在消息队列中放置一条WM_PAINT消息。在本章的后面我们将会看到,当窗口过程收到WM_PAINT消息时,它可以获得无效矩形的坐标。而在其他任何时候,它都可以通过调用GetUpdateRect函数来获取这些坐标。
●需要注意的是,虽然系统会自动处理无效区域的重绘,但是在某些情况下,如果不需要立即更新窗口,或者你希望在一个特定的时间(例如在一系列的更改全部完成后)再更新,可以使用ValidateRect或ValidateRgn函数来清除无效区域,避免马上触发WM_PAINT消息。然后在适当的时候再用InvalidateRect或InvalidateRgn函数来设置无效区域并触发窗口的重绘。
使用这些函数进行手动的无效化和验证,可以帮助提高软件的性能和用户体验,避免反复的无效化和重绘导致的闪烁和性能下降。
总的来说,处理无效矩形区域是Windows图形界面编程中的一个重要概念,需要了解其工作机制,以便在编写和维护代码时能够更好地控制窗口的更新和重绘。
3.1.2 设备环境
■设备环境
在Windows系统中,设备环境(Device Context,简称DC)是一个用于描述设备(如显示器、打印机等)的抽象概念。设备环境DC实际上是GDI内部维护的一个数据结构,包含了绘图的所有信息,可以看作是绘图的工作环境,比如线条宽度、颜色、字体等各种绘图参数。当我们需要对一个设备进行绘图操作时,需要获取到该设备对应的设备环境。
设备环境被分为三种基本类型:显示设备环境(Display DC)、打印设备环境(Printer DC)和内存设备环境(Memory DC)。打印设备环境我们将在第十三章讲述,内存设备环境将在第十四章讲述。本章我们仅涉及到显示设备环境。
程序在绘制前必须先获取一个设备环境句柄。在获取句柄后,Windows会在内部的设备环境结构中填入默认的属性值。在以后的章节中,我们会学到一些GDI函数可以改变这些默认值。有些GDI函数则能让你得到当前的属性值。还有些GDI函数让你真正在当前的客户区进行绘图。
当程序完成了对客户区的绘制后,它必须释放设备环境句柄。在程序释放句柄之后,这个句柄不再有效并且不能再被使用。程序必须在处理同一条消息的过程中获取句柄和释放句柄。我们不能在两条消息中间传递一个环境设备句柄,唯一的例外是通过调用CreateDC函数创建的设备环境——本章不讨论这个函数。
显示设备环境是与显示器关联的设备环境,用于在屏幕上绘图。一般通过GetDC、BeginPaint等函数获取。
■获取设备环境句柄的方法
●方法一:在之前的示例代码中,我们在处理WM_PAINT消息时,窗口过程首先调用BeginPaint函数擦去无效区域的背景以便绘图。同时还会填充ps结构的各个字段。
PAINTSTRUCT结构定义如下:
typedef struct tagPAINTSTRUCT
{
HDC hdc ;
BOOL fErase ;
RECT rcPaint ;
BOOL fRestore ;
BOOL fIncUpdate ;
BYTE rgbReserved[32] ;
} PAINTSTRUCT ;
程序只能使用前三个字段,其他的字段供Windows内部使用。hdc是设备环境句柄,而BeginPaint函数的返回值就是设备环境句柄的值。多数情况下,fErase字段被设置为FALSE(0)。这意味着Windows在先前的BeginPaint函数中已经擦除了无效区域的背景。(如果想在窗口过程中自定义背景擦除方式,必须自己处理WM_ERASEBKGND消息)。在WINMAIN初始化时,用于注册窗口类的WNDCLASS结构中的bhrBackground字段指定了一个画刷,Windows就使用这个画刷来擦除背景。很多windows程序指定了一个白色的背景画刷。
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ; //窗口背景色
但是当你的程序通过调用InvalidateRect函数使客户区中的一个矩形无效时,该函数的最后一个参数即指定背景是否要被擦除。如果参数是FALSE(0),Windows将不会擦除背景,同时在调用BeginPaint函数后,PAINTSTRUCT结构的fErase字段的值将是TRUE(非零)。
PAINTSTRUCT结构的rcPaint字段是一个RECT类型的结构。我们知道RECT结构使用4个字段left、top、right和bottom定义了一个矩形。PAINTSTRUCT结构中的rcPaint字段定义了无效矩形的边界。
PAINTSTRUCT结构中的rcPaint矩形不仅是无效矩形,而且还是一个“裁剪”矩形,如果无效区不是一个矩形,Windows将把绘制限制在这个区域内。
在处理WM_PAINT消息时,在调用BeginPaint之前调用以下的函数可以在该更新矩形之外绘制:
InvalidateRect(hwnd,NULL,TRUE);
这个调用将整个客户区无效化,并使其后调用的BeginPaint擦除原有的背景。如果将最后一个参数设为FALSE,则随后调用的BeginPaint函数将不会擦除背景,原来的背景将被保留。
通常来说,对于windows程序最方便的做法是在收到WM_PAINT消息后,简单的重绘客户区而不管rcPaint结构的值如何。例如,如果客户区的显示包括一个圆,但是只有一部分落在无效区域里时,只画圆的一部分并不实际。简单的做法是重绘整个圆。在使用BeginPaint返回的设备环境句柄时,Windows无论如何也不会在rcPaint定义的矩形之外绘制。
BeginPaint函数的返回值就是设备环境句柄,通常将它保存在一个名为hdc的变量中。
HDC hdc;
HDC数据类型为32位无符号整数。此后,程序可以调用任何一个需要设备环境句柄的GDI函数了,例如TextOut。调用EndPaint函数将释放设备环境句柄。
通常处理WM_PAINT消息的代码如下:
case WM_PAINT:
hdc = BeginPaint(hwnd,&ps);
[使用GDI函数]
EndPaint(hwnd,&ps);
return 0;
窗口过程处理WM_PAINT消息时必须成对地调用BeginPaint和EndPaint函数。如果窗口过程不处理WM_PAINT消息,WM_PAINT消息就会被传送给Windows默认的窗口过程DefWindowProc。代码如下:
case WM_PAINT:
BeginPaint(hwnd,&ps);
EndPaint(hwnd,&ps);
return 0;
这里除了将原来的无效区域有效化以外,在两个函数之间不包含任何代码。
以下代码是错误的:
case WM_PAINT:
return 0;//WRONG!
由于部分客户区是无效的,Windows才会在消息队列中放置一条WM_PAINT消息。除非调用BeginPaint和EndPaint函数,否则windows不会将那个区域有效化。因此Windows将会不停的发送WM_PAINT消息,直到永远。
●方法二:调用GetDC函数获取设备环境句柄。通常绘图都是在处理WM_PAINT消息时完成。但是有时候也不一定,如果在其他消息处理时需要调用GDI绘图函数绘图,就需要使用设备环境句柄,而设备环境句柄不可以跨消息使用,只能重新获取。在其他消息模块中是不可以使用BeginPaint和EndPaint函数的,改用GetDC函数获取设备环境句柄,使用ReleaseDC函数释放设备环境句柄。与BeginPaint和EndPaint类似,GetDC和ReleaseDC必须成对使用。
与从BeginPaint函数返回的设备环境句柄不同,从GetDC返回的设备环境句柄中的裁剪矩形是整个客户区。这意味着可以在客户区任意部分绘制,而不仅仅是在无效矩形里,也就是说如果不存在无效矩形也没关系。与BeginPaint不同,GetDC不会将无效区域有效化。如果需要将整个客户区有效化,可以调用函数:
ValidateRect(hwnd,NULL);
通常GetDC和ReleaseDC函数用于处理键盘消息(例如字处理程序中)或者鼠标消息(例如绘图程序中)。使用这两个函数,程序可以在收到用户的键盘或鼠标输入时及时的绘制客户区,而不必为了生成WM_PAINT消息去刻意使客户区的一部分无效化。但是,即使程序在处理非WM_PAINT消息时进行了绘制,它仍然必须收集足够的信息以便在收到WM_PAINT时能更新显示。
另一个与GetDC类似的函数是GetWindowDC。GetDC返回的是窗口客户区的设备环境句柄,GetWindowDC返回的则是整个窗口的设备环境句柄。例如程序员可以使用GetWindowDC返回的设备环境句柄在窗口的标题栏输出,相应的,程序也必须要处理WM_NCPAINT(非客户区绘制)消息。
3.1.3 字体与字符
■系统字体
设备环境同时还定义了在调用TextOut时Windows使用的字体。在Windows系统中,有许多预装的字体可以供你在应用程序中使用。这些字体通常存储在C:\Windows\Fonts文件夹中。字体包含各种类型,默认的字体称为“系统字体”或SYSTEM_FONT(标识符定义在WINDI.H头文件中)。系统字体是Windows在标题栏、菜单和对话框中使用的默认字体。
在早期的Windows中,系统字体是一种宽字体,还有一种字体是非等宽字体。
1.等宽字体:每个字符占用的宽度是相等的。无论是宽字符如’W’还是窄字符如’I’,每个字符在显示时都会有相同的宽度。这种字体在一些特定的场景中非常有用,如编程中就经常会使用等宽字体。因为在代码中,对于空格和缩进的显示,等宽字符可以让结构更清晰、对齐更准确。常见的等宽字体有Courier、Monaco和Consolas等。
2.非等宽字体:也被称为比例字体,各个字符和标点符号占据的宽度可以不同。这类字体在大多数的文档、网站和图形用户界面中应用更为广泛,因为它们有更好的阅读体验和视觉效果。比如在非等宽字体中,字符’I’的宽度要远小于字符’W’。常见的非等宽字体有Arial、Times New Roman和Verdana等。
这两种字体的选择取决于你的特定需求。如果需要对齐或固定宽度等特性,可以选择等宽字体。而对于大部分的文档排版和网页设计,非等宽字体通常是更好的选择,因为它们给人的阅读感更流畅、自然。
系统字体是一种“点阵字体”:每个字符由像素点构成。第十六章我们将学习TrueType字体,由轮廓定义字符。在某种程度上,系统字体中字符的大小取决于显示器的大小:系统字体的涉及要求能够在显示器上起码显示25行80列。
■字符大小
为了用TextOut函数显示多行文本,就需要知道字体中字符的尺寸。字符的高度可以决定一行文字的垂直位置,而字符的平均宽度可以决定下一栏文本的水平位置。
系统字体中字符的平均宽度没有固定值,这取决于显示器的分辨率。Windows屏幕分辨率低,字符就大,分辨率高,字符就小一些。程序可以通过调用GetSystemMetrics函数来获取用户界面的尺寸。同样的,通过GetSystemMetrics函数,程序可以获取字体尺寸。GetSystemMetrics函数需要一个设备环境句柄,因为它会返回该设备环境中当前选定的字体的信息。Windows将把字符尺寸的各种值复制到类型TEXTMETRIC的结构中,该结构在WINGDI.H头文件中定义,有20个字段,但我们只需要关心其中的前7个:
typedef struct tagTEXTMETRIC
{
LONG tmHeight; //字符高度
LONG tmAscent; //字符上部高度(基线以上)
LONG tmDescent; //字符下部高度(基线以下)
LONG tmInternalLeading, //由tmHeight定义的字符高度的顶部空间数目
LONG tmExternalLeading, //夹在两行之间的空间数目
LONG tmAveCharWidth, //平均字符宽度
LONG tmMaxCharWidth, //最宽字符的宽度
其他结构栏位
} TEXTMETRIC, * PTEXTMETRIC ;
这些字段的值的单位取决于设备环境中当前选定的映射模式。默认的映射模式MM_TEXT——以像素为单位。
在调用GetSystemMetrics函数前,首先要定义一个结构变量,通常命名为tm:
TEXTMETRIC tm;
需要获取字号时,首先获取设备环境句柄,然后调用GetSystemMetrics函数:
hdc = GetDC (hwnd) ;
GetTextMetrics (hdc, &tm) ;
ReleaseDC (hwnd, hdc) ;
之后就可以检查文字尺寸结构中的值,并保存以后需要使用的部分。
■文本尺寸
在TEXTMETRICS结构中有设备环境中当前字体的各种信息。但字体的纵向尺寸仅由其中的5项决定,图3-2显示了其中4项。
图3-2 字体的尺寸
其中最重要的是tmHeight,它是tmAscent和tmDescent的和。这两个值分别是字符在基线之上和之下的最大高度。间距leading是两行文字之间的空间。在TEXTMETRICS结构里,内部间距包含在tmAscent中。该间距通常被用于希腊重音符号。tmInternalLeading的值可以设为0,在这种情况下,带重音符号的字符会稍微短一点,以便把重音符号包括在内。
tmExternalLeading并不包含在tmHeight的值里。该字段是字体设计者建议在两行文字间留出的空间大小。在显示多行文字时,可以选择接受或者不理会这个建议。
tmAveCharWidth是小写字符的加权平均宽度;
tmMaxCharWidth是字体中最宽的字符的宽度。在等宽字体中,这两个值是一样的。
在本章的范例程序中还有另一种字符宽度:大写字符的平均宽度。该值大小通常可以按tmAveCharWidth的1.5倍计算。
值得重视的是,系统字体的尺寸取决于Windows运行时的显示分辨率,有时还取决于用户选定的系统字号。Windows提供了与设备无关的图形界面。但程序员也需要注意:不要在Windows应用程序中猜测文本的尺寸,不要使用固定的值,应该通过调用GetTextMtetricd函数来获取这些信息。
■文本格式化
Windows系统运行时,系统字体不会变化。因此,应用程序调用GetTextMetrics函数的最好的时机是在窗口过程处理WM_CREATE消息时。WM_CREATE消息是窗口过程收到的第一条消息。
假设你的Windows程序需要在客户区内显示几行文本,你需要获取字符的宽度和高度。在窗口过程中,可以定义两个变量来保存:
static int cxChar,cyChar;
变量名的前缀c代表“cont”这里代表像素。和x,y结合,表示宽度和高度。这里被定义为静态变量,也可以被定义为全局变量。
以下代码为获取系统字体的高度和宽度:
case WM_CREATE:
hdc = GetDC (hwnd) ;
GetTextMetrics (hdc, &tm) ;
cxChar = tm.tmAveCharWidth ;
cyChar = tm.tmHeight + tm.tmExternalLeading ;
ReleaseDC (hwnd, hdc) ;
return 0 ;
在窗口中,每一行文本显示在上一行文本下方cyChar个像素处。
通常需要显示的是格式化的数字和字符串。如第二章所述,不能用传统的工具printf函数,但是可以使用sprintf函数或者Windows版的sprintf——wsprintf。这些函数与printf功能类似,区别在于格式化后的字符保存在一个字符串里。这个字符串可以通过TextOut函数输出到窗口中。方便的是,sprintf函数和wsprintf函数的返回值是字符串的长度,这可以传给TextOut函数作为iLength参数。
下面的代码显示了 wsprintf 与 TextOut 的典型组合:
int iLength ;
TCHAR szBuffer [40] ;
[其他程序行]
iLength = wsprintf (szBuffer, TEXT ("The sum of %i and %i is %i"), iA, iB, iA + iB) ;
TextOut (hdc, x, y, szBuffer, iLength) ;
对于这样简单的情况,可以将 iLength 的定义值与 TextOut 放在同一条语句中,从而无需定义 iLength:
TextOut (hdc, x, y, szBuffer,
wsprintf (szBuffer, TEXT ("The sum of %i and %i is %i"), iA, iB, iA + iB)) ;
虽然这样子写起来不好看,但是功能与前者是一样的。
3.1.4 第19练:获取系统配置信息No.1
/*---------------------------------------------------------
SYSMETS.H -- 系统配置信息结构数组(参见《附录B》)
-----------------------------------------------------------*/
/*------------------------------------------------------------------------
019 编程达人win32 API每日一练
第19个例子SYSMETS1.C:文本输出---获取系统配置信息No.1
TEXTMETRIC结构
GetDC函数
ReleaseDC函数
GetTextMetrics函数
SetTextAlign函数
GetSystemMetrics函数
注意:窗口客户区无法全部显示所有信息。
(c) www.bcdaren.com 编程达人
-----------------------------------------------------------------------*/
#include <windows.h>
#include <tchar.h>
#include "sysmets.h" //定义系统信息结构数组及NUMLINES(显示行数)
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("SysMets1");
…(略)
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static int cxChar; //字符平均宽度
static int cxCaps; //字符间距
static int cyChar; //字符行距
HDC hdc;
int i;
PAINTSTRUCT ps;
TCHAR szBuffer[10];
TEXTMETRIC tm; //物理字体的基本信息
switch (message)
{
case WM_CREATE:
hdc = GetDC(hwnd); //获取设备环境句柄
//从设备环境中获取程序当前的默认字体信息,存放到TEXTMETRIC结构变量中
GetTextMetrics(hdc, &tm);
cxChar = tm.tmAveCharWidth;//字符平均宽度
//tm.tmPitchAndFamily字体间距,tmPitchAndFamily字段的低位决定字体是否
//为等宽字体:1代表变宽字体,0代表等宽字体。
//字体间距cxCaps设为cxChar的1.5倍。1表示变宽字体
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));
//设置文本对齐标志,向右和顶部对齐
SetTextAlign(hdc, TA_RIGHT + TA_TOP);
//获取系统信息参数值
TextOut(hdc, 22 * cxCaps + 40 * cxChar, cyChar * i, szBuffer,
//<tchar.h>头文件通用函数替换wsprintf函数
_stprintf_s(szBuffer, 10,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);
}
/**************************************************************************
TEXTMETRIC结构:包含物理字体的基本信息。所有大小均以逻辑单位指定;也就是说,它们取决于显示上下文的当前映射模式。
typedef struct tagTEXTMETRIC { // tm
LONG tmHeight; //字符高度
LONG tmAscent; //字符上部高度(基线以上)
LONG tmDescent; //字符下部高度(基线以下)
LONG tmInternalLeading, //由tmHeight定义的字符高度的顶部空间数目
LONG tmExternalLeading, //夹在两行之间的空间数目
LONG tmAveCharWidth, //平均字符宽度
LONG tmMaxCharWidth, //最宽字符的宽度
LONG tmWeight; //字体的粗细轻重程度
LONG tmOverhang, //加入某些拼接字体上的附加高度
LONG tmDigitizedAspectX, //字体设计所针对的设备水平方向
LONG tmDigitizedAspectY, //字体设计所针对的设备垂直方向
BCHAR tmFirstChar; //为字体定义的第一个字符
BCHAR tmLastChar; //为字体定义的最后一个字符
BCHAR tmDefaultChar; //字体中所没有字符的替代字符
BCHAR tmBreakChar; //用于拆字的字符
BYTE tmItalic, //字体为斜体时非零
BYTE tmUnderlined, //字体为下划线时非零
BYTE tmStruckOut, //字体被删去时非零
BYTE tmPitchAndFamily, //字体间距(低4位)和族(高4位)
BYTE tmCharSet; //字体的字符集
} TEXTMETRICA, *PTEXTMETRICA, *NPTEXTMETRICA, *LPTEXTMETRICA;
*******************************************************************************
GetDC函数:检索句柄用于指定窗口的客户区或整个屏幕的设备上下文(DC)。您可以在后续的GDI函数中使用返回的句柄来绘制DC。
设备上下文是一个不透明的数据结构,其值由GDI内部使用。
HDC GetDC(
HWND hWnd //要获取其DC的窗口的句柄。如果此值为NULL,则GetDC检索整个屏幕的DC。
);
返回值
如果函数成功,则返回值是指定窗口的客户区DC的句柄。
如果函数失败,则返回值为NULL。
*******************************************************************************
ReleaseDC函数:释放设备上下文(DC),释放它,以供其他应用程序使用。
ReleaseDC功能的效果取决于DC的类型。它仅释放公共DC和窗口DC。它对class or private DC无效。
int ReleaseDC(
HWND hWnd, //要释放其DC的窗口的句柄。
HDC hDC //要释放的DC的句柄。
);
返回值
返回值指示是否释放了DC。如果释放了DC,则返回值为1。
如果未释放DC,则返回值为零。
*******************************************************************************
GetTextMetrics函数:填充与度量当前所选字体指定的缓冲区。
BOOL GetTextMetrics(
HDC hdc,//设备上下文的句柄。
LPTEXTMETRIC lptm//指向接收文本指标的TEXTMETRIC结构的指针。
);
返回值
如果函数成功,则返回值为非零。
如果函数失败,则返回值为零。
*******************************************************************************
SetTextAlign函数:为指定设备环境设置文字对齐标志。
UINT SetTextAlign(
HDC hdc, //设备上下文的句柄。
UINT align //通过使用以下列表中的值的掩码进行文本对齐。
);
返回值
如果该函数成功,则返回值为先前的文本对齐设置。
如果函数失败,则返回值为GDI_ERROR
*******************************************************************************
GetSystemMetrics函数:检索指定的系统指标或系统配置设置。
int GetSystemMetrics(
int nIndex //要检索的系统指标或配置设置
);
返回值
类型:int
如果函数成功,则返回值是请求的系统指标或配置设置。
如果函数失败,则返回值为 0。GetLastError不提供扩展的错误信息。
*/
【注意】很明显,窗口客户区内只显示了部分内容。
图3-3 显示系统配置信息