再上一篇:3.4 关于文本显示的更多内容
上一篇:4.1 图形设备接口
主页
下一篇:4.3 设备坐标系和逻辑坐标系
再下一篇:4.4 映射模式
文章列表

4.2 设备描述表

《Windows 下的 C/C++高级编程》讲述Windows环境下调用Win32 API函数程序设计

在前面的程序中,我们已经用到了设备描述表。读者应当还有印象,要显示图形(包括文字),必须先获得设备描述表句柄。

设备描述表(Device Context,简称为DC),是GDI内部保存的数据结构。设备描述表与特定的显示设备(如显示器、打印机等)相关。对于显示器,设备描述表总是与显示器上特定的窗口相关。设备描述表中保存了显示图形所需使用的各种参数值,例如,显示的颜色、显示的坐标、显示的方式和背景的颜色等。

4.2.1 获取设备描述表句柄

当应用程序需要绘图的时候,必须先获得设备描述表句柄。在获得了该句柄以后,Windows会以默认的属性值填充内部的属性表结构。随后,应用程序需要调用相应的GDI函数,以指定的属性值代替需要改变的默认值。当绘图完毕后,应用程序必须释放设备描述表句柄。

通常,应用程序使用两种方法来获取设备描述表句柄。

■ 方法一:BeginPaint和EndPaint

■ 通常,应用程序在响应WM_PAINT消息时进行绘图操作,此时,需调用BeginPaint函数来获取设备描述句柄,使用完毕后需调用EndPaint函数来释放句柄。BeginPaint函数定义如下:

HDC BeginPaint(

HWND hwnd, // 所属窗口句柄

LPPAINTSTRUCT lpPaint // 绘图信息结构体指针

);

■ 该函数需要所属窗口句柄和一个绘图信息结构体指针作参数,其返回值就是一个设备描述表句柄。BeginPaint 函数一般在准备绘制时,将无效矩形区域的背景擦除,并将默认值填入参数lpPaint指向的绘图信息结构体。其返回值(设备描述表句柄)是一个32位的无符号整数。随后的程序就可以使用该设备描述表句柄,进行各种GDI操作。最后应用程序需要调用EndPaint函数释放该句柄。EndPaint函数定义如下:

BOOL EndPaint(

HWND hWnd, // 所属窗口句柄

CONST PAINTSTRUCT *lpPaint // 绘图信息结构体指针

);

参数hWnd为所属窗口句柄,参数lpPaint为需要释放的设备描述表句柄。

通常处理WM_PAINT消息的形式如下:

HDC hdc;

HWND hwnd;

PAINTSTRUCT ps;

#第80页~

第4章 图形显示

case WM_PAINT:

hdc = BeginPaint( hwnd, &ps );

// 其他GDI操作

EndPaint( hwnd, &ps );

return 0;

在处理WM_PAINT消息时,必须成对地调用BeginPaint和EndPaint函数。而且,应用程序应当在处理同一个消息期间获取并释放设备描述表句柄,而不应该在处理不同的消息时分别获取和释放。

如果窗口函数不处理WM_PAINT消息,则将WM_PAINT消息传递给Windows的默认窗口函数(DefWindowProc)处理。DefWindowProc函数中处理WM_PAINT消息的代码如下:

case WM_PAINT:

hdc = BeginPaint( hwnd, &ps );

// 其他GDI操作

EndPaint( hwnd, &ps );

return 0;

这段代码并不进行任何绘图操作,只是简单地将ps指定的无效矩形区域变为有效。

请注意,如果应用程序用如下方法处理WM_PAINT消息,那么用户也许将不得不强行中断程序。

case WM_PAINT:

return 0;

如果当前窗口用户区的某一部分变为无效,则Windows会将一个WM_PAINT消息放到消息队列中。如果不调用BeginPaint和EndPaint函数(同时,也不调用ValidateRect函数),该无效区域不会变为有效,于是,Windows将会发送另一个WM_PAINT消息,并且会一直发送下去。

■ 方法二:GetDC和ReleaseDC

虽然通常在处理 WM_PAINT 消息时更新窗口的用户区,但有时也需要在处理非WM_PAINT消息时绘制用户区的部分或者全部。例如,通常在创建窗口时,使用设备描述表句柄来获取设备描述表信息。

在处理非WM_PAINT消息时可以通过调用GetDC函数来获取设备描述表句柄。GetDC函数的定义如下:

HDC GetDC(

HWND hWnd // 所属窗口的句柄

);

该函数仅需一个参数,即窗口函数所属窗口的句柄。该函数返回设备描述表句柄。当使用完毕后,应当调用ReleaseDC函数释放该设备描述表句柄。ReleaseDC函数定义如下:

int ReleaseDC(

HWND Wnd, // 所属窗口的句柄

HDC hDC // 需要释放的设备描述表句柄

#第81页~ Windows下的C/C++高级编程

);

参数hWnd为窗口函数所属窗口的句柄。参数hDC即需要释放的设备描述表句柄。

通常如下使用这两个函数:

HDC hdc;

HWND hwnd;

hdc = GetDC( hwnd );

// 其他GDI操作

ReleaseDC( hwnd, hdc );

同样,GetDC与 ReleaseDC函数必须成对使用,并且,不应当在处理一个消息时调用GetDC函数而在处理另一个消息时调用ReleaseDC函数。

GetDC函数与BeginPaint有两点不同:

■ 通过BeginPaint函数所获得的操作区域是用户区中的无效矩形区域,后继的绘图操作只能在该无效矩形区域内进行,而该区域以外的操作将被忽略。GetDC所获得的操作区域则是整个用户区,其后继操作可以在用户区的任意部分进行,而不只是在无效矩形区域内。

■ BeginPaint函数会自动将无效矩形区域变为有效。而GetDC函数则不会将任何无效矩形区域变为有效,如果需要使整个用户区变为有效,则可以调用ValidateRect 函数,并将其第二个参数设为NULL。

4.2.2 设备描述表属性

Windows使用设备描述表来保存控制GDI函数如何在显示设备上工作的“当前属性”。例如,在使用TextOut 函数时,应用程序只需指定设备表述表句柄、文本显示的起始位置坐标、需要显示的文本及其长度,而不需指定文本的字体、颜色、背景色和字符间距等。Windows可以从设备描述表中获取这些信息(默认值)。

当应用程序使用GetDC或BeginPaint函数获得一个设备描述表句柄时,Windows会自动用默认值设置其所有的属性。应用程序可以通过相应的GDI函数调用获取、修改所有的属性值。表4-1列出了一些常用的设备描述表属性、相应的默认值以及相应的读取和修改GDI函数:

表4-1 设备描述表属性表

设备描述表属性 默认值 获取函数 设置函数Mapping Mode(映射模式) MM_TEXT GetMapMode SetMapMode

Window Origin(窗口原点) (0,0) GetWindowOrgEx SetWindowOrgEx

OffsetWindowOrgExViewport Origin(视图原点) (0,0) GetViewportOrgEx SetViewportOrgEx

OffsetViewportOrgEx

(1,1) GetWindowExtEx SetWindowExtExWindow Extents(窗口范围) SetMapMode

ScaleWindowExtEx

#第82页~

第4章 图形显示

续表

设备描述表属性 默认值 获取函数 设置函数

(1,1) GetViewportExtEx SetViewportExtExViewport Extents(视图范围) SetMapMode

ScaleViewportExtExPen(笔) BLACK_PEN SelectObject SelectObject

Brush(刷子) WHITE_BURS SelectObject SelectObject

H

Brush Origin(刷子原点) (0,0) GetBrushOrgEx SetBrushOrgExFont(字体) SYSTEM_FON SelectObject SelectObject

T

Bitmap(位图) N/A SelectObject SelectObject

(0,0) GetCurrentPositionEx MoveTo

Current Position(笔、刷子等 LineTo

的当前位置) PolylineTo

PolyBezierTo

Background Color(背景色) White GetBkColor SetBkColor

Background Mode(背景模式) OPAQUE GetBkMode SetBkMode

Text Color(文本颜色) Black GetTextColor SetTextColor

Drawing Mode(绘图模式) R2_COPYPEN GetROP2 SetROP2

BLACKONWH GetStretchBltMode SetStretchBltModeStretching Mode(缩放模式) ITE

Polygon Fill Mode(多边形填 ALTERNATE GetPolyFillMode SetPolyFillMode充模式)

Intercharacter Spacing(字符间 0 GetTextCharachterExtra SetTextCharacterExtra距)

None GetClipBox SelectClipReg

IntersectClipRgnClipping Region(裁剪区) OffsetClipRgn

SelectObject

ExcludeClipRect

SelectClipPath

表4-1所列属性,有些前面已经介绍过,大部分将在后面的章节中讲解。

4.2.3 保存设备描述表

通常,在调用GetDC或BeginPaint函数以获取设备描述表句柄时,Windows会自动用默认值填充设备描述表的各个字段,应用程序需要随后更改其中那些希望更改的字段。但是,

#第83页~ Windows下的C/C++高级编程

在应用程序调用ReleaseDC或EndPaint函数以释放设备描述表句柄时,所作的所有更改都会丢失。这就意味着,如果应用程序需要使用非默认的设备描述表属性,则必须在每次获取设备描述表句柄时显示地初始化设备描述表。通常的操作如下:

HDC hdc;

HWND hwnd;

PAINTSTRUCT ps;

case WM_PAINT:

hdc = BeginPaint( hwnd, &ps );

// 初始化设备描述表属性

// 其他GDI操作

EndPaint( hwnd, &ps );

但是,也许有时需要在释放设备描述表句柄之后,仍然保存应用程序对设备描述表属性所作的更改,以便在下一次调用GetDC或BegingPaint函数时仍然能够使用更改后的属性值,这就需要保存设备描述表。

首先,需要在注册窗口时,在窗口风格中添加CS_OWNDC标志。

wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;

这样就使得所有基于该窗口类所创建地窗口都会拥有自己的设备描述表。该设备描述表将一直存在,直到窗口被关闭。

如果设置了窗口的 CS_OWNDC 风格,就只需要初始化设备描述表一次,通常在处理WM_CREATE消息时完成这项工作。

HDC hdc;

HWND hwnd;

case WM_PAINT:

hdc = GetDC( hwnd );

// 初始化设备描述表属性

ReleaseDC( hwnd, hdc );

这些属性值在显示地调用其他GDI函数加以改变之前将一直有效。

如果希望改变某些设备描述表属性的值,用改变后的属性进行绘图,然后再恢复原来的设备描述表属性,就可以先调用SaveDC函数来保存当前的设备描述表。

iSavedDC = SaveDC( hdc );

然后,可以改变一些设备描述表的属性值,并进行绘图操作。最后,调用RestoreDC函数来恢复原来的设备描述表。

RestoreDC( hdc, iSavedDC );

可以在调用RestoreDC函数之前多次调用SaveDC函数。然后用如下形式调用RestoreDC函数来恢复倒数第n次所保存的设备描述表信息。

RestoreDC( hdc, -n); // -n表示恢复倒数第n次所保存的设备描述表信息

#第84页~

第4章 图形显示