api (三)文本字符输出 (转)
在使用Win32编程时,我们常常要输出文本到窗口上,Windows所有的文本字符或者图形输出都是通过图形设备接口(GDI)进行的,Windows的三大核心组件之一的GDI32.dll封装了所有的文本和图像输出。
- GDI基本知识
Windows下要绘图和输出文本,都是通过GDI(Graphics Device Interface,图形设备接口)完成的,GDI是windows在绘制图文时的设备上下文环境,包括画笔、画刷、字体、位图等多种与绘制有关的对象。设备环境(DC)在绘制中起至关重要的作用。几乎所有的绘制(包括图形和文本)都与设备环境相关,注意“环境”的意义,就跟我们在画布上绘画和写字一样,绘制时的画布是哪个,用的什么笔,什么颜色,填充整个画布时用的什么刷子等等,这就是我们的绘制时的环境,而Windows绘图的DC设备上下文就是一样的道理。设备环境句柄(HDC)就是用来描述DC的句柄,可以说,只要有了这个句柄,就具备了在窗口上输出图形和文本的条件。你获得了窗口客户区的HDC,就可以在窗口客户区上画;你获得了窗口的非客户区HDC,就可以在它上面画;你获得了桌面HDC,就可以直接在桌面上画……
获取设备环境句柄的方法有两种:一是处理WM_PAINT消息时,通过BeginPaint函数返回。另外一种就是通过GetDC、GetWindowDC的API函数获取。
- 通过WM_PAINT消息获取DC
Windows在检测到需要重新绘制或者刷新窗口时,会主动要求处理WM_PAINT消息。比如在如下情况下就会主动求处理:
- 用户移动一个窗口,导致原来被盖住的部分窗口显示出来。
- 用户调整窗口的大小,并且窗口风格类型设置为CS_HREDRAW和CS_VREDRAW。
- 程序调用ScrollWindow或者ScrollDC函数滚动客户区。
- 程序调用InvalidateRect或者InvalidateRgn函数,该函数显示生产一条WM_PAINT消息。
我们可以在该消息中完成图文绘制,该消息的处理具有特定的格式,必须在实际绘制前调用BeginPaint,在绘制完成后调用EndPaint函数,也就是说我们需要把所有绘制的功能都放到这两个函数之间,并且HDC也只能在这之间使用,不能保存起来在其它地方使用。使用WM_PAINT有一个好处,就是windows会自己计算哪些区域需要更新,也就是说只有真正变化的地方才会更新,这样更新的代价会降低到最小。
- 通过API函数获取HDC
我们还可以通过GetDC、GetWindowDC函数来获取HDC,但是要注意,通过这个来获取的HDC,可以保存起来在其它时候使用,但是要记住一旦窗口有更新,必须想办法重新绘制,否则就会消失了。最后在使用完毕后需要调用ReleaseDC来释放,否则会造成资源泄露。
- 创建特定字体
我们平时最常见的文本输出是不需要自己创建字体的,因为常见的对象都有系统预定义好的。如果想输出点特殊(非系统预定义的)字体,就需要我们创建并自动选入设备环境。创建字体主要有CreateFont和CreateFontIndirect,这两个函数的参数都很多,基本一样,具体用法看后面的实例。
- 实现文本绘制
有了上面的基础,我们就可以通过Windows的API来完成文本输出了,常用的文本输出函数有TextOut、DrawText、DrawTextExt、ExtTextOut等,这些函数基本都有相似的参数,比如hdc,坐标位置,字符串。下面TextOut、DrawText、ExtTextOut为例来说明如何在Windows窗口中如何输出文本,其它请查看MSDN的用法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
#include <windows.h>
#include <tchar.h>
;
;
)
{
;
;
;
;
;
;
;
;
;
;
;
;
;
)
{
;
;
}
// window class name
// window caption
// window style
// initial x position
// initial y position
// initial x size
// initial y size
// parent window handle
// window menu handle
// program instance handle
// creation parameters
;
;
)
{
;
;
}
;
}
)
{
;
;
)
{
:
;
:
{
;
;
;
;
;
;
;
;
;
;
;
;
;
;
// nHeight, 所创建字体的字符高度
// nWidth, 字体的字符平均宽度
// nEscapement, 字符输出方向与水平向右的方向所成角度,以0.1度为单位
// nOrientation, 字符与基线的角度,以0.1度为单位
// nWeight, 字符颜色的深浅度
// bItalic, 斜体属性标志(FALSE:正常字体,TRUE:斜体)
// bUnderline, 下划线属性标志(FALSE:无下划线,TRUE:有下划线)
// cStrikeOut, 删除线属性标志(FALSE:无删除线,TRUE:有删除线)
// nCharSet, 字符集标识0:ANSI字符集,1:系统缺省字符集
// nOutPrecision, 输出精度
// nClipPrecision, 剪切精度
// nQuality, 输出品质
// nPitchAndFamily, 字符间距
// lpszFacename, 现有系统TrueType字体名称
;
;
;
;
;
;
}
;
:
;
;
}
;
}
|
程序运行,点击鼠标左键后效果如下:
程序中的DrawText、ExtTextOut能设置文本输出的矩形范围,超出部分是看不见的,从运行结果我们也可以看出有两行显示不全,就是由于设置的显示范围小的缘故。
另外ExtTextOut函数还可以设置字符的间距,运行结果的第三行就是这种自己设置间距不一样的结果。
本程序还用CreateFont函数创建了一个斜体、右上排列的文本串。通过上例,我们把常用的文本输出作为实例展示给大家,只要好好对照实例代码,在结合MSDN的说明,再加上本系列的第一篇的Windows编程基本框架,一定可以掌握好Windows编程的基本文本输出。