3.9、填充空隙
在点划线、短划线笔或影线刷子的使用中,点和短划线之间的空隙以及刷子中的阴影间隙的着色取决于设备对象中定义的背景方式和背景颜色。缺省的背景方式是OPAQUE,即Windows用背景色填充空隙,缺省的背景颜色是白色,即与大多数程序在窗口类别中用作清除窗口背景的WHITE_BRUSH型刷子相一致。可以通过调用函数SetBkColor设背景色,使用函数GetBkColor获得设备对象中定义的当前背景色(见表3-14)。
表3-14-1 SetBkColor 函数
| 用 途 |
设置当前的背景色。 |
| 原 型 |
| DWORD SetBkColor( |
|
| HDC hDC, |
设备对象句柄 |
| COLORREF crColor |
新的背景色,RG颜色值 |
| ) |
| |
| 返回值 |
返回作为一种颜色值的当前的背景色。若小于0,则出错。 |
注释:如果背景方式为OPAQUE,那么GDI就用背景色填充设计的行距、笔、刷子中阴影间隙,以及各字符中的间隙。如果设备不能表示由crColor参数指定的RGB颜色值,此函数将当前背景色设置为最接近的物理色(纯颜色),并返回之。
表3-14-2 GetBkColor 函数
| 用 途 |
返回指定设备的当前背景色。 |
| 原 型 |
| DWORD GetBkColor( |
|
| HDC hDC |
设备对象句柄 |
| ) |
| |
| 返回值 |
当前背景色的RGB颜色值。 |
当前背景方式决定Windows是否填充空隙。函数SetBkMode及GetBkMode用于设置和获取背景方式,如表3-15。
表3-15-1 SetBkMode 函数
| 用 途 |
设置与文本和线型一起使用的背景方式。背景方式决定在显示文本、刷子或非实线的普通笔型之前,GDI是否要将设备显示表面已有显示内容用背景色清除。 |
| 原 型 |
| int SetBkMode( |
|
| HDC hDC |
设备对象句柄 |
| int nBkMode |
背景方式。见后面说明 |
| ) |
| |
| 返回值 |
返回OPAQUE或TRANSPARENT,以说明先前的背景方式。 |
| 常量 |
说明 |
| OPAQUE |
在文本、刷子或笔绘图之前,用当前背景色填充设备显示表面 |
| TRANSPARENT |
背景保留不变 |
表3-15-2 GetBkMode 函数
| 用 途 |
返回设备的背景方式。 |
| 原 型 |
| int GetBkMode( |
|
| HDC hDC |
设备对象句柄 |
| ) |
| |
| 返回值 |
返回当前背景方式(OPAQUE或TRANSPARENT)。 |
3.10、设置文本属性 有一些设备对象属性影响文本。缺省时设备对象所绘制的文本颜色为黑色。可以使用函数SetTextColor或函数GetTextColor设置或获取设备对象中的文本颜色,如表3-17。
表3-16-1 SetTextColor 函数
| 用 途 |
设置文本颜色。 |
| 原 型 |
| DWORD SetTextColor( |
|
| HDC hDC |
设备对象句柄 |
| COLORREF crColor |
指定的文本颜色(RGB值) |
| ) |
| |
| 返回值 |
返回先前的文本颜色(RGB值)。 |
注释:如果设备不支持指定的颜色,则设置成最接近的物理颜色。
表3-16-2 GetTextColor 函数
| 用 途 |
设置当前的文本颜色。 |
| 原 型 |
| DWORD GetTextColor( |
|
| HDC hDC |
设备对象句柄 |
| ) |
| |
| 返回值 |
当前使用的文本颜色(RGB值)。 |
下面的程序是对3.4及3.7节的程序修改后所形成的一个示例程序,这个程序演示了在程序中设置文本属性方法。
// 3-10.c
#include <stdio.h>
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int PASCAL WinMain(
HINSTANCE hInstance, // 应用程序的实例句柄
HINSTANCE hPrevInstance, // 该应用程序前一个实例的句柄
LPSTR lpszCmdLine, // 命令行参数串
int nCmdShow ) // 程序在初始化时如何显示窗口
{
... ...
} LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HBRUSH OrgBrush, hBrush;
static int xChar, yChar;
int line;
char szBuffer[256];
HDC hDC;
char ch;
PAINTSTRUCT ps;
TEXTMETRIC tm;
FILE *fp;
switch(message)
{
case WM_CREATE:
OrgBrush = GetClassWord(hwnd, GCW_HBRBACKGROUND);
hBrush = CreateHatchBrush(HS_DIAGCROSS, RGB(255, 255, 0)
SetClassWord(hwnd, GCW_HBRBACKGROUND, hBrush);
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
hDC = GetDC(hwnd);
GetTextMetrics(hDC, &tm);
xChar = tm.tmAveCharWidth;
yChar = tm.tmHeight + tm.tmExternalLeading;
ReleaseDC(hwnd, hDC);
return 0;
case WM_PAINT:
hDC = BeginPaint(hwnd, &ps);
SetBkMode(hDC, OPAQUE);
SetTextColor(hDC, RGB(255, 0, 0));
SetBkColor(hDC, RGB(0, 255, 0));
SetMapMode(hdc, MM_ANISOTROPIC);
SetWindowExt(hdc, 1, 1);
SetViewportExt(hdc, xChar, yChar);
line = 0;
if((fp = fopen("3-10.c", "r")) != NULL)
{
while(!feof(fp)) {
int i = 0;
while((ch = fgetc(fp)) != '\n' && ch != EOF)
szBuffer[i++] = (char)ch;
TextOut(hDC, xChar, line*yChar, szBuffer, i);
line++;
}
fclose(fp);
}
EndPaint(hwnd, &ps);
return 0L;
case WM_DESTROY:
SetClassWord(hwnd, GCW_HBRBACKGROUND, OrgBrush);
DeleteObject(hBrush);
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
} 修改这个程序,将背景方式设置为TRANSPARENT,观察程序的运行结果。
3.11、公用和私用显示设备 在前面,我们曾介绍说,Windows维护着五个公用的显示设备对象,当窗口对象需要绘制其用户区时,使用函数GetDC()或BeginPaint()从Windows那里借用。一般而言,函数GetDC()和BeginPaint()所借用来的公用显示设备对象的初始属性为表3-1中所给出的缺省属性,窗口对象可以使用有关的函数改变这些属性,以满足其绘制要求。在绘制工作完成以后,窗口对象应将显示设备对象归还给Windows。但注意,当调用ReleaseDC()或EndPaint()函数将公用显示设备对象归还Windows后,对显示设备对象的属性所做的改变也就丢失了。这样,当窗口对象再次借用显示设备对象时,显示设备对象的初始属性仍为缺省属性,窗口对象在每次使用非缺省属性进行绘制之前,都必须使用有关的函数设置显示设备对象的属性。
另外的一种情况是当窗口对象在一段程序中改变了一些设备对象属性,在使用改变后的设备对象属性工作之后,窗口对象又要使用原先的设备对象属性继续工作,对这种情况,一种比较方便的方法是通过使用函数SaveDC()和RestoreDC来简化对设备对象的管理,这两个函数的使用说明见表3-17。
表3-16-1 SaveDC 函数
| 用 途 |
该函数用于保存其参数所标识的设备对象的当前属性信息,它通过将这些属性信息拷贝到一个设备对象环境栈中来实现。 |
| 原 型 |
| int SaveDC( |
|
| HDC hDC |
设备对象句柄 |
| ) |
| |
| 返回值 |
返回一个序数值来反映被保存的设备对象,如果该函数在执行中出错,则返回0。 |
注释:该函数可被调用多次来分别保存多个设备对象的多个属性信息。
表3-16-2 RestoreDC 函数
| 用 途 |
恢复设备对象的属性信息。 |
| 原 型 |
| BOOL RestoreDC( |
|
| HDC hDC |
设备对象句柄 |
| int nSaveDC |
指定要被恢复的属性信息,可以是函数SaveDC()返回的值或为-1,若为-1,则设备对象被恢复为设备对象环境栈顶所保存的属性信息。 |
| ) |
| |
| 返回值 |
非零表示恢复成功,零表示失败。 |
注释:该函数通过拷贝设备对象环境栈中保存的属性信息来恢复指定的设备对象属性。如果由参数nSaveDC指定的设备对象信息不处于环境栈的栈顶,那以函数RestoreDC()会不断地删除栈顶信息,直到找到由参数nSaveDC所指定的设备对象信息为止,这些被删除的信息永远被丢失了。
下面的程序片段用于演示函数SaveDC()和RestoreDC()使用方法:
// ...... int nSaveID = SaveDC(hDC);
SetBkMode(hDC, OPAQUE);
SetTextColor(hDC, RGB(255, 0, 0));
SetBkColor(hDC, RGB(0, 255, 0));
SetMapMode(hDC, MM_ANISOTROPIC);
SetWindowsExt(hDC, 1, 1);
SetViewportExt(hDC, xChar, yChar); // ...... RestoreDC(nSaveID); // ...... 使用公用显示设备对象的优点是,这些显示设备对象为系统中的所有应用程序共享。但不足之处在于存在与借用、设置和归还显示设备对象有关的许多工作,对一些复杂的绘图程序,或使用非缺省属性的应用程序,使用公用显示设备对象会增加程序的编码量,并有可能影响到应用程序的效率。对这些情况,程序员可以为一个或多个窗口对象指定使用私用显示设备对象,当在注册窗口类时,为该窗口类指定CS_OWNDC风格参数,这时,由这种窗口类所创建的窗口对象都拥有自己的私用显示设备对象。
使用私用显示设备对象的优点在于,由于私用的显示设备对象仅供一个窗口对象专用,这样,窗口对象在一条消息处理完备以后从窗口函数返回之前也不需要归还显示设备对象。窗口对象可以将显示设备对象的句柄保存在一个静态生存期的变量中,供自己使用。例如,窗口对象在处理WM_CREATE消息时设置设备的属性,而在处理WM_PAINT或其他消息时直接使用所设置对象属性。
// 3-11.c
#include <stdio.h>
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int PASCAL WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpszCmdLine,
int nCmdShow)
{
char szAppName[] = "DispText";
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
HBRUSH hBrush;
HDC hDC;
int xChar, yChar;
TEXTMETRIC tm;
hBrush = CreateHatchBrush(HS_DIAGCROSS, RGB(255, 255, 0));
if (!hPrevInstance) {
wndclass.style = CS_VREDRAW | CS_HREDRAW | CS_OWNDC;
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;
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass))
return FALSE;
}
hwnd = CreateWindow(
szAppName,
"Display Text",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL );
hDC = GetDC(hwnd);
GetTextMetricse(hDC, &tm);
xChar = tm.tmAveCharWidth;
yChar = tm.tmHeight + tm.tmExternalLeading;
SetBkMode(hDC, OPAQUE):
SetTextColor(hDC, RGB(255, 0, 0));
SetBkColor(hDC, RGB(0, 255, 0));
SetMapMode(hDC, MM_ANISOTROPIC);
SetWindowExt(hDC, 1, 1)
SetViewportExt(hDC, xChar, yChar);
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while( GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
ReleaseDC(hwnd, hDC);
DeleteObject(hBrush);
return msg.wParam;
} LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int line;
char szBuffer[256];
HDC hDC;
char ch;
PAINTSTRUCT ps;
FILE *fp;
switch(message)
{
case WM_PAINT:
hDC = BeginPaint(hwnd, &ps);
line = 0;
if((fp = fopen("3-11.c", "r")) != NULL)
{
while(!feof(fp)) {
int i = 0;
while((ch = fgetc(fp)) != '\n' && ch != EOF)
szBuffer[i++] = (char)ch;
TextOut(hDC, xChar, line*yChar, szBuffer, i);
line++;
}
fclose(fp);
}
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
} 在一个窗口对象使用私用显示设备对象的情况下,函数GetDC()和BeginPaint()返回的句柄标识的设备对象是窗口的私用显示设备对象。从这个程序还可以看出,私用的显示设备对象保持当前设置的设备属性,对私用的显示设备对象,不存在“借用”和“归还”之说。但使用CS_OWNDC只影响到从GetDC和BeginPaint检索到的设备对象,而不会影响到使用别的函数(例如GetWindowDC()等函数)检索到的设备对象。
一个私用显示设备对象大约占用200字节,所有的字节都从GDI模块的局部堆中分配,而这个堆由系统中当前正运行的所有应用程序共享。如果系统中的所有应用程序都使用私用显示设备对象,那将会用完GDI的局部堆,导致系统崩溃。因此,除非必要,应用程序一般不使用私用显示设备对象。
介于使用公用和私用显示设备对象之间的是使用类显示设备对象。若在注册窗口类时指定了CS_CLASSDC风格参数,则该窗口类拥有一个可供该类所有窗口对象(包括在该应用程序的其它实例中所创建的窗口对象)共用的显示设备对象。这种类型的显示设备对象被称为类显示设备对象。类显示设备对象由于被该类的所有窗口对象共享,因此,一个窗口对象在使用类显示设备对象时需要从类中借用,并在使用完之后归还给类,否则,该类的其它对象就无法使用类显示设备对象。但有一点应引起注意,类显示设备对象同私用显示设备对象一样,也保持当前设置的属性,即使在归还类的情况下也是如此。这就是说,如果该类的一个窗口对象改变了该显示设备对象的属性,那么,也要影响到基于该窗口类所创建的所有窗口对象(包括在该应用程序的其它实例中所创建的窗口对象)。因此,类显示设备对象较难使用,但它相对于私用显示设备对象而言,可以节省一些内存空间。
上一页 [1] [2] [3] [4]