画笔
摘录于《Windows程序(第5版,珍藏版).CHarles.Petzold 著》P131
5.3.5 使用现有画笔
调用本节介绍的任何一个画线函数时,Windows 都会使用当前选入设备环境的“画笔”来绘制直线。画笔决定了线条的颜色、宽度和样式,样式可以是实线、点线或者虚线。画笔的默认设备环境 BLACK_PEN。该画笔会绘制一条实心的宽度为 1 个像素的黑色线条。BLACK_PEN 是 Windows 提供的三种“备用画笔”(stock pen)的一种。另外两种分别是 WHITE_PEN 和 NULL_PEN。NULL_PEN 表示不绘制任何图形的画笔。你也可以创建自己的画笔。
在 Windows 程序中,使用句柄来操作画笔。Windows 头文件 WINDEF.H 定义画笔句柄的类型为 HPEN。可以使用这个类型定义一个变量(例如 hPen):
[cpp] view plaincopy
- HPEN hPen;
[cpp] view plaincopy
- hPen = GetStockObject (WHITE_PEN);
[cpp] view plaincopy
- SelectObject (hdc, hPen);
除了明确地定义 hPen 变量,还可以将 GetStockObject 调用和 SelectObject 调用组合在一条语句中:
[cpp] view plaincopy
- SelectObject (hdc, GetStockObject (WHITE_PEN));
[cpp] view plaincopy
- SelectObject (hdc, GetStockObject (BLACK_PEN));
SelectObject 函数返回一个先前选入设备环境的画笔的句柄。如果使用一个新的设备环境,并且调用:
[cpp] view plaincopy
- hPen = SelectObject (hdc, GetStockObject (WHITE_PEN));
[cpp] view plaincopy
- SelectObject (hdc, hPen);
5.3.6 创建、选择和删除画笔
尽管使用备用对象中的画笔非常方便,但只能使用实心的黑色画笔、实心的白色画笔或者没有画笔三种情况。如果想获得更丰富的效果,则必须创建自己的画笔。
这里是创建画笔的一般过程:调用 CreatePen 或者 CreatePenIndirect 函数创建一个“逻辑画笔”,它只是说明你想得到一个什么样的画笔。这些函数会返回一个逻辑画笔的句柄。然后需要调用 SelectObject 函数将画笔选入设备环境中。接着,就可以使用这个新的画笔来绘制线条。一次只能有一支画笔被选入设备环境。释放设备环境之后(或者将其他画笔选入设备环境之后),需要调用 DeleteObject 函数来删除你创建的逻辑画笔。此后,画笔的句柄不再有效。
逻辑画笔是一个“GDI 对象”,一个程序可以创建 6 种GDI 对象,它是其中之一,其他 5 种分别是画刷、位图、区域、字体和调色板。除了调色板之外,所有这些对象都通过 SelectObject 函数选入设备环境。
下面三条规则控制画笔等 GDI 对象的使用:
- 最终应当删除你所创建的所有 GDI 对象。
- 当 GDI 对象被选入一个有效的设备环境时,不要删除它。
- 不要删除备用对象。
这些规则都是有道理的,但是有时候会有点棘手。下面我们将通过例子来帮助理解这些规则。
CreatePen 函数的一般语法如下:
[cpp] view plaincopy
- hPen = CreatePen (iPenStyle, iWidth, crColor);
其中,参数 iPenStyle 决定画笔绘制的是实现或者虚线或电线。这个参数可以使用定义在 WINGDI.H 头文件中的下列标识符。图 5-18 显示了每种样式产生的线条。
对于 PS_SOLID、PS_NULL 和 PS_INSIDEFRAME 样式,参数 iWidth 表示画笔的宽度。当 iWidth 值为 0 时,Windows 把画笔的宽度设定为 1 个像素。备用画笔总是 1 个像素宽。如果指定使用虚线或点线样式,同时把画笔宽度设定为大于 1 个 像素,那么 Windows 会使用实心的画笔来代替。
CreatePen 的参数 crColor 是一个 COLORREF 值,它用来指定画笔的颜色。对所有的除了 PS_INSIDEFRAME 之外的画笔样式,当将画笔选入到设备环境时,Windows 将该颜色转换为设备所能表示的最近的纯色。PS_INSIDEFRAME 画笔样式是唯一能够使用抖动色的画笔样式,并且只有当画笔宽度大于 1 时才如此。
PS_INSIDEFRAME 画笔样式用于填充区域的函数时有另外一个奇特之处。当使用非 PS_INSIDEFRAME 样式的画笔样式时,如果用于绘制轮廓的画笔宽度大于 1 个像素,那么画笔的中心会处于边界之上,这样画出的轮廓线部分将会在边框之外。但是对于 PS_INSIDEFRAME 画笔样式,整个轮廓线都会在边框内。
也可以通过建立一个类型为 LOGPEN(“逻辑画笔”)的结构,并调用 CreatePenIndirect 函数来建立一个画笔。如果你的程序在初始化时需要创建很多不同的画笔,这种方法会很有效。
为了使用 CreatePenIndirect 函数,首先要定义一个类型为 LOGPEN 的结构:
[cpp] view plaincopy
- LOGPEN logpen;
可以通过将该结构的地址传递到 CreatePenIndirect 函数来创建画笔:
[cpp] view plaincopy
- hPen = CreatePenIndirect (&logpen);
注意:CreatePen 和 CreatePenIndirect 函数不需要设备环境句柄。在调用 SelectObject 之前,这些函数创建的逻辑画笔和设备环境没有任何联系,可以为几种不同的设备,例如屏幕和打印机,使用相同的逻辑画笔。
这里给出创建、选择和删除画笔的一种方法。假定程序使用三种画笔(宽度为 1 的黑色画笔、宽度为 3 的红色画笔和黑色的点线画笔)。可以首先定义存储这些画笔的句柄的静态变量:
[cpp] view plaincopy
- static HPEN hPen1, hPen2, hPen3;
[cpp] view plaincopy
- hPen1 = CreatePen(PS_SOLD, 1, 0);
- hPen2 = CreatePen(PS_SOLD, 3, RGB(255, 0, 0));
- hPen3 = CreatePen(PS_DOT, 0, 0);
[cpp] view plaincopy
- SelectObject(hdc, hPen2);
- [line-drawing functions]
- SelectObject(hdc, hPen1);
- [line-drawing functions]
[cpp] view plaincopy
- DeleteObject(hPen1);
- DeleteObject(hPen2);
- DeleteObject(hPen3);
可以随时创建画笔,还可以将 CreatePen 和 SelectObject 调用组合到一条语句中:
[cpp] view plaincopy
- SelectObject (hdc, CreatePen (PS_DASH, 0, RGB(255, 0, 0));
[cpp] view plaincopy
- DeleteObject (SelectObject (hdc, GetStockObject (BLACK_PEN)));
下面给出另一个方法。当将一支画笔选入到一个新创建的设备环境时,保存 SelectObject 返回的画笔句柄:
[cpp] view plaincopy
- hPen = SelectObject (hdc, CreatePen (PS_DASH, 0, RGB (255, 0, 0)));
[cpp] view plaincopy
- DeleteObject (SelectObject (hdc, hPen));
如果有一个画笔的句柄,LOGPEN 结构中各个字段成员的值可以通过调用 GetObject 函数获得:
[cpp] view plaincopy
- GetObject (hPen, sizeof(LOGPEN), (LPVOID) &logpen);
如果需要获得当前被选入设备环境的画笔句柄,则调用:
[cpp] view plaincopy
- hPen = GetCurrentObject (hdc, OBJ_PEN);
我将在第 17 章讨论另外一个画笔创建函数:ExtCreatePen。
5.3.7 填充空隙
使用点式画笔和虚线画笔会带来这样一个问题:点和虚线之间的空隙是什么颜色呢?你觉得呢?
空隙的颜色是由设备环境的两个属性(背景模式和背景颜色)决定的。默认的背景模式是 OPAUQE(不透明),这就意味着 Windows 使用背景颜色来填充空隙,背景颜色在默认时是白色。这与许多程序在窗口类中用 WHITE_BRUSH 来擦除窗口背景的做法相同。
可以通过调用下面的函数来改变 Windows 填充空隙的背景颜色:
[cpp] view plaincopy
- SetBKColor (hdc, crColor);
也可以通过将背景模式改为 TRANSPARENT(透明)来阻止 Windows 填充空隙:
[cpp] view plaincopy
- SetBKMode (hdc, TRANSPARENT);