现在的位置: 首页 > 自动控制 > 工业·编程 > 正文

Win32 关键点总结(2):输出文本

2012-09-10 12:19 工业·编程 ⁄ 共 6609字 ⁄ 字号 评论 1 条

16 有效矩形和无效矩形

窗口过程一旦接受到WM_PAINT消息之后,就准备更新整个客户区,但往往只需更新一个较小的区域。这个区域就称为“无效区域”。正是客户区内存在无效区域,才提示Windows将一个WM_PAINT消息放入消息队列。

Windows内部为每个窗口保存一个“绘图信息结构”,这个结构包含了包围无效区域的最小矩形的坐标以及其他信息,这个矩形就叫做“无效矩形”。

如果在窗口过程处理WM_PAINT消息之前,客户区又有一个区域变为无效,那么Windows计算出一个包围两个无效区域的新的无效矩形,并将这个变化后的信息放在绘制信息结构中。

一个消息队列在一个时刻只能有一个WM_PAINT消息在队列中。

窗口过程可以调用InvalidateRect使客户区变为无效。如果消息队列包含一个WM_PAINT消息,那么Windows将计算出新的无效矩形;否则,就在消息队列中添加一个WM_PAINT消息。

在处理WM_PAINT消息期间,窗口过程在调用了BeginPaint之后,整个客户区就会变得有效。

程序也可以显式调用ValidateRect函数使客户区内的任意矩形区域变得有效。如果这条调用使整个客户区都有效,那么将在当前消息队列中删除WM_PAINT消息。

》》》Win32 关键点总结(1):窗口和消息

17 设备描述表

要在窗口的客户区绘图,可以使用Windows的图形设备接口GDI函数。

设备描述表DC是GDI内部保存的数据结构。

设备描述表与特定的显示设备有关。

设备描述表中的有些值是图形化的“属性”,如指出颜色、背景色、坐标映射方式等。

当程序要绘图时,必须先获取设备描述表句柄。在获取了该句柄之后,Windows用默认的属性值填充设备描述表结构的内部各域。

当程序在客户区绘图完毕后,必须释放设备描述表句柄。句柄被释放后不再有效,也不再使用。程序必须在处理单个消息期间获取和释放句柄。

18 获取设备描述表句柄的方法之一

在使用WM_PAINT消息时,使用这种方法。它涉及到BeginPaint和EndPaint两个函数。

在处理WM_PAINT消息时,窗口过程首先调用BeginPaint。BeginPaint函数一般在准备绘制时导致无效区域的背景被擦除。BeginPaint返回的值是设备描述表句柄,这一返回值通常被保持在叫做hdc的变量中。

HDC hdc;

HDC数据类型定义为32位的无符号数。

然后,程序就可以使用需要设备描述表句柄的GDI函数了。

调用EndPaint即可释放设备描述表句柄。

一般地,处理WM_PAINT消息的形式如下:

case WM_PAINT:

    hdc = BeginPaint(hwnd, &ps);

    使用GDI函数

    EndPaint(hwnd, &ps);

    return 0;

处理WM_PAINT消息时,必须成对地调用BeginPaint和EndPaint。

19 绘图信息结构

Windows为每一个窗口保存一个绘图信息结构。这就是PAINTSTRUCT,定义如下:

typedef struct tagPAINTSTRUCT {

    HDC         hdc;         

    BOOL        fErase;       

    RECT        rcPaint;

    BOOL        fRestore;

    BOOL        fIncUpdate;

    BYTE        rgbReserved[32];

} PAINTSTRUCT

在程序调用BeginPaint时,Windows填充该结构的各个字段。用户程序只需要使用前三个字段。

hdc是设备描述表句柄。

fErase通常被标识为FLASE,这意味着Windows已经擦除了无效矩形的背景。

如果程序通过调用Windows函数InvalidateRect使客户区中的矩形失效,那么该函数的最后一个参数会指定fErase的值。如果指定0,那么在稍后的PAINTSTRUCT里面的fErase会被设置为TRUE。

rcPaint是RECT结构,定义了无效矩形的边界。RECT结构中的left、top、right、bottom以像素点为单位。此时,Windows将绘图操作限制在此RECT结构定义的矩形范围内,如果要在无效矩形外绘图,应该在调用BeginPaint之前,使用如下调用:

InvalidateRect(hwnd, NULL, TRUE);

它将使整个客户区无效,并擦除背景。

20获取设备描述表句柄的方法之二

要得到窗口客户区的设备描述表句柄,可以调用GetDC来获取句柄。在使用完后调用ReleaseDC;

hdc = GetDC(hwnd);

使用GDI函数

ReleaseDC(hwnd, hdc);

GetDC和ReleaseDC函数必须成对地使用。

GetDC返回的设备描述表句柄具有一个剪取矩形,等于整个客户区。

GetDC不会使任何无效区域变为有效,要是整个客户区有效,需要调用:

ValidateRect(hwnd, NULL);

一般可以调用GetDC和ReleaseDC来对键盘消息、鼠标消息作出反应。

21 TextOut细节

TextOut是用于显示文本的最常用的GDI函数。语法是:

TextOut(hdc, x, y, psText, iLength);

第一个参数:设备描述表句柄,既可以是GetDC的返回值,也可以是BeginPaint的返回值。

第二个参数:定义客户区内字符串的开始位置的水平坐标。

第三个参数:定义客户区内字符串的开始位置的垂直坐标。

第四个参数:指向要输出的字符串的指针。

第五个参数:字符串中字符的个数。如果psText中的字符是Unicode的,那么串中的字节数就是iLength值的两倍。

设备描述表还定义了一个剪取区域。

对于从GetDC获取的设备描述表句柄,默认的剪取区是整个客户区。

对于从BeginPaint获取的设备描述表句柄,默认的剪取区是无效区域。

Windows不会在剪取区域之外的任何位置显示字符串。

22 字符大小

要用TextOut显示多行文本,就必须确定字体的字符大小,可以根据字符的高度来定位字符的后续行,以及根据字符的宽度来定位字符的后续列。

系统字体的字符高度和平均宽度取决于视频显示器的像素大小。

程序可以调用GetSystemMetrics函数来确定关于用户界面构件大小的信息。

程序可以调用GetTextMetrics函数来确定字体大小。

metric是度量的意思。

TEXTMETRIC的结构:

typedef struct tagTEXTMETRIC

{

    LONG        tmHeight;

    LONG        tmAscent;

    LONG        tmDescent;

    LONG        tmInternalLeading;

    LONG        tmExternalLeading;

    LONG        tmAveCharWidth;

    LONG        tmMaxCharWidth;

    其他域

} TEXTMETRIC, *PTEXTMETRIC;

要使用GetTextMetrics函数,需要先定义一个通常被称为tm的结构变量:

TEXTMETRIC tm;

在需要确定文本尺寸时,先要获取设备描述表句柄,再调用GetTextMetrics:

hdc = GetDC(hwnd);

GetTextMetrics(hdc, &tm);

操作;

ReleaseDC(hwnd,hdc);

23 文本尺寸

字体的纵向大小由5个值确定:

① tmHeight,等于tmAscent加上tmDescent。这两个值表示了基线上下字符的最大纵向高度。

② tmAscent,基线以上的高度

③ tmDescent,基线以下的高度

④ tmInternalLeading,重音号和字符之间的距离,如ü中的u和两点的距离。

⑤ tmExternalLeading,一般用于多行文本间行距的调整。

字符的横向大小由2个值确定:

① tmAveCharWidth,小写字母加权平均宽度。

② tmMaxCharWidth,字体中最宽字符的宽度。

对于等宽字体,tmAveCharWidth和tmMaxCharWidth这两个值相等。

大写字母的平均宽度比较复杂,如果:

① 字体是等宽字体,那么大写字母的平均宽度等于tmAveCharWidth。

② 字体是变宽字体,那么大写字母的平均宽度等于tmAveCharWidth*1.5。

判断字体是否是变宽字体,可以通过TEXTMETRIC结构中的tmPitchAndFamily域的低位判断,如果低位是1,那么是变宽字体,如果是0,那么是等宽字体。

大写字母宽度 = (tm.tmPitchAndFamily & 1 ? 3 : 2) / 2 * 小写字母宽度

24 格式化文本

在一次Windows对话期间,系统字体的大小不会改变,因此在程序运行过程中,只需要调用一次GetTextMetric。最好是在窗口过程中处理WM_CREATE消息时进行此调用。

假设要编写一个Windows程序,在客户区显示多行文本,这需要先获取字符宽度和高度。可以在窗口过程内定义两个变量来保存字符宽度和总的字符高度。

case WM_CREATE:

   hdc = BeginPaint(hwnd, &pt);

   GetTextMetric(hdc, &tm);

   cxChar = tm.tmAveCharWidth;                                  小写字母宽度

   cyChar = tm.Height + tm.tmExternalLeading;                      字母高度

   cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) / 2 * tm.tmAveCharWidth; 大写字母宽度

   EndPaint(hwnd, &pt);

   return 0;

25 客户区的大小

窗口最大化之后的客户区大小,可以通过以SM_CXFULLSCREEN和SM_CYFULLSCREEN为参数调用GetSystemMetric来获得。

要确定客户区的大小,最好的方法是在窗口过程处理WM_SIZE消息。在窗口大小改变时,就会产生WM_SIZE消息。传给窗口过程的lParam参数的低位字中包含客户区的宽度x,高位字中包含客户区的高度y。要保存这些尺寸,可以定义两个int型变量来保存。

static int cxClient,cyClient;

然后在WM_SIZE消息处理中:

case WM_SIZE:

    cxClient = LOWORD(lParam);

    cyClient = HIWORD(lParam);

    return 0;

用cyClient/cyChar可以得到客户区可以显示的文本总行数。

26 滚动条的范围和位置

每个滚动条都有一个相关的范围和位置。这是一对整数。当滚动框在滚动条的顶部(左部)时,滚动框的位置是范围的最小值;在滚动条的底部(右部)时,滚动框的位置是范围的最大值。

在默认情况下,滚动条的范围是0~100,但将范围改变为更方便于程序的数值也是很容易的:

SetScrollRange(hwnd, iBar, iMin, iMax, bRedraw);

其中hwnd为该窗口的句柄。

    iBar为SB_VERT或SB_HORZ。

    iMin和iMax为范围。

    bRedraw,如果要Windows根据新范围重绘滚动条,则设置为TRUE。

滚动框的位置不是连续的,而是离散的整数值。

可以使用SetScrollPos在滚动条范围内设置新的滚动框位置:

SetScrollPos(hwnd, iBar, iPos, bRedraw);

参数iPos是新位置,必须在iMin至iMax的范围内。

Windows提供了类似的函数GetScrollRange和GetScrollPos来获取滚动条的当前范围和位置。

27 滚动条消息

在用鼠标单击滚动条或者拖动滚动框时,Windows都给窗口过程发生WM_VSCROLL或WM_HSCROLL消息。在滚动条上的每个鼠标动作都至少产生两个消息,一个在按下鼠标键时产生,一个在释放鼠标键时产生。

WM_VSCROLL和WM_HSCROLL也带有wParam和lParam消息参数。

lParam只用于作为子窗口而创建的滚动条(通常在对话框内)。

wParam消息参数被分为一个低位字和一个高位字。

低位字是一个数值,指出了鼠标对滚动条进行的操作。这个数值被看作一个“通知码”。通知码以SB开头。

#define SB_LINEUP           0

#define SB_LINELEFT         0

#define SB_LINEDOWN        1

#define SB_LINERIGHT        1

#define SB_PAGEUP           2

#define SB_PAGELEFT         2

#define SB_PAGEDOWN        3

#define SB_PAGERIGHT        3

#define SB_THUMBPOSITION   4

#define SB_THUMBTRACK     5

#define SB_TOP               6

#define SB_LEFT              6

#define SB_BOTTOM           7

#define SB_RIGHT             7

#define SB_ENDSCROLL        8

当把鼠标的光标放在滚动框上并按住鼠标键时,就产生SB_THUMBPOSITION和SB_THUMBTRACK消息。

当wParam的低位字是SB_THUMBTRACK时,wParam的高位字是用户在拖动滚动框时的当前位置。

当wParam的低位字是SB_THUMBPOSITION时,wParam的高位字是用户释放鼠标后滚动框的最终位置。

28 滚动条信息函数

滚动条文档指出SetScrollPos、SetScrollRange、GetScrollPos、GetScrollRange函数是过时的。

在Win32 API中,升级了2个滚动条函数,称作SetScrollInfo和GetScrollInfo。这些函数完成上述4个函数的全部功能,并增加了2个新特性。

第一个功能设计滚动框的大小。滚动框的大小称作页面大小。算法是:

滚动框大小 / 滚动长度 ≈ 页面大小 / 范围 ≈ 显示的文档数量 / 文档的总大小

可以使用SetScrollInfo来设置页面大小。

第二个功能是GetScrollInfo函数,它可以获取32位的范围值。

SetScrollInfo和GetScrollInfo函数的语法是:

SetScrollInfo(hwnd, iBar, &si, bRedraw);

GetScrollInfo(hwnd, iBar, &si);

iBar参数是SB_VERT或SB_HORZ。

bRedraw可以是TRUE或FALSE,指出了是否要Windows重新绘制计算了新信息后的滚动条。

两个函数的第三个参数是SCROLLINFO结构,定义为:

typedef struct tagSCROLLINFO

{

    UINT    cbSize;

    UINT    fMask;

    int       nMin;

    int       nMax;

    UINT    nPage;

    int       nPos;

    int       nTrackPos;

}   SCROLLINFO

在程序中,可以定义如下的SCROLLINFO结构类型:

SCROLLINFO si;

在调用SetScrollInfo或GetScrollInfo函数之前,必须将cbSize自动设置为结构的大小:

si.cbSize = sizeof(si);或si.cbSize = sizeof(SCROLLINFO);

fMask:把fMask字段设置为以SIF前缀开头的一个或多个标识,来获取或设置里面的结构中域的值。

① SIF_RANGE:用于获取或设置滚动条的范围

② SIF_POS:用于获取或设置滚动框的位置

③ SIF_PAGE:用于获取或设置滚动条的页面大小

④ SIF_TRACKPOS:用于获取或设置滚动框移动时的位置

目前有 1 条留言    访客:0 条, 博主:0 条 ,引用: 1 条

    外部的引用: 1 条

    • Win32 关键点总结(3):图形基础 « 求索阁

    给我留言

    留言无头像?