画笔

来源:互联网 发布:linux服务启动关闭管理 编辑:程序博客网 时间:2024/06/11 17:45

摘录于《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 plain copy
  1. HPEN hPen;  
调用 GetStockObject 函数可以获取备用画笔的句柄。例如想使用名为 WHITE_PEN 的备用画笔。可以按照如下方式获取画笔句柄:

[cpp] view plain copy
  1. hPen = GetStockObject (WHITE_PEN);  
现在必须把该画笔选入设备环境:

[cpp] view plain copy
  1. SelectObject (hdc, hPen);  
现在,当前画笔变成白色画笔。也就是说在该函数调用之后,绘制的所有线条都将使用 WHITE_PEN,直到将另一种画笔选入设备环境 或者你释放了设备环境句柄。

        除了明确地定义 hPen 变量,还可以将 GetStockObject 调用和 SelectObject 调用组合在一条语句中:

[cpp] view plain copy
  1. SelectObject (hdc, GetStockObject (WHITE_PEN));  
接着,如果想恢复使用 BLACK_PEN,也可以只使用一条语句来获取那个备用对象(BLACK_PEN)的句柄,同时将它选入设备环境:     

[cpp] view plain copy
  1. SelectObject (hdc, GetStockObject (BLACK_PEN));  

        SelectObject 函数返回一个先前选入设备环境的画笔的句柄。如果使用一个新的设备环境,并且调用:

[cpp] view plain copy
  1. hPen = SelectObject (hdc, GetStockObject (WHITE_PEN));  
那么设备环境中的当前画笔就变为 WHITE_PEN,变量 hPen 将是 BLACK_PEN 画笔的句柄。可以接着通过下面的调用将 BLACK_PEN 重新选入设备环境:

[cpp] view plain copy
  1. SelectObject (hdc, hPen);  

5.3.6  创建、选择和删除画笔

        尽管使用备用对象中的画笔非常方便,但只能使用实心的黑色画笔、实心的白色画笔或者没有画笔三种情况。如果想获得更丰富的效果,则必须创建自己的画笔。

        这里是创建画笔的一般过程:调用 CreatePen 或者 CreatePenIndirect 函数创建一个“逻辑画笔”,它只是说明你想得到一个什么样的画笔。这些函数会返回一个逻辑画笔的句柄。然后需要调用 SelectObject 函数将画笔选入设备环境中。接着,就可以使用这个新的画笔来绘制线条。一次只能有一支画笔被选入设备环境。释放设备环境之后(或者将其他画笔选入设备环境之后),需要调用 DeleteObject 函数来删除你创建的逻辑画笔。此后,画笔的句柄不再有效。

        逻辑画笔是一个“GDI 对象”,一个程序可以创建 6 种GDI 对象,它是其中之一,其他 5 种分别是画刷、位图、区域、字体和调色板。除了调色板之外,所有这些对象都通过 SelectObject 函数选入设备环境。

        下面三条规则控制画笔等 GDI 对象的使用:

  • 最终应当删除你所创建的所有 GDI 对象。
  • 当 GDI 对象被选入一个有效的设备环境时,不要删除它。
  • 不要删除备用对象。

这些规则都是有道理的,但是有时候会有点棘手。下面我们将通过例子来帮助理解这些规则。

        CreatePen 函数的一般语法如下:

[cpp] view plain copy
  1. 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 plain copy
  1. LOGPEN logpen;  
这个结构由三个字段:lopnSytle(无符号整型,或 UINT)表示画笔样式,lopnWidth(一个 POINT 结构)是以逻辑单位表示的画笔宽度,还有 lopnColor(COLORREF)表示画笔的颜色。Windows 仅使用 lopnWidth 结构中的 x 字段来设置画笔的宽度,y 字段会被忽略。

        可以通过将该结构的地址传递到  CreatePenIndirect 函数来创建画笔:

[cpp] view plain copy
  1. hPen = CreatePenIndirect (&logpen);  


注意:CreatePen 和 CreatePenIndirect 函数不需要设备环境句柄。在调用 SelectObject 之前,这些函数创建的逻辑画笔和设备环境没有任何联系,可以为几种不同的设备,例如屏幕和打印机,使用相同的逻辑画笔。

        这里给出创建、选择和删除画笔的一种方法。假定程序使用三种画笔(宽度为 1 的黑色画笔、宽度为 3 的红色画笔和黑色的点线画笔)。可以首先定义存储这些画笔的句柄的静态变量:

[cpp] view plain copy
  1. static HPEN hPen1, hPen2, hPen3;  
在处理 WM_CREATE 消息时,可以创建这三种画笔:

[cpp] view plain copy
  1. hPen1 = CreatePen(PS_SOLD, 1, 0);   
  2. hPen2 = CreatePen(PS_SOLD, 3, RGB(255, 0, 0));  
  3. hPen3 = CreatePen(PS_DOT, 0, 0);  
在处理 WM_PAINT 消息时(或者在任何拥有有效的设备环境句柄时),可以将其中任何一支画笔选入到设备环境,并且使用它来绘制线条:

[cpp] view plain copy
  1. SelectObject(hdc, hPen2);  
  2. [line-drawing functions]  
  3. SelectObject(hdc, hPen1);  
  4. [line-drawing functions]   
在处理 WM_DESTROY 消息时,可以删除这三种画笔:

[cpp] view plain copy
  1. DeleteObject(hPen1);  
  2. DeleteObject(hPen2);  
  3. DeleteObject(hPen3);  
这是用于创建、选择和删除画笔最直接的方法。但是很显然,程序必须知道需要使用什么样的画笔。因此可能需要在每个 WM_PAINT 消息处理时创建画笔,并在调用 EndPaint  函数后删除它们。(也可以在调用 EndPaint 函数前删除它们,但是需要小心,不要删除已被选入设备环境中的当前画笔。)

        可以随时创建画笔,还可以将 CreatePen 和 SelectObject 调用组合到一条语句中:

[cpp] view plain copy
  1. SelectObject (hdc, CreatePen (PS_DASH, 0, RGB(255, 0, 0));  
现在,在绘制直线时,将使用一个红色的虚线画笔。红色虚线绘制完成后,可以删除画笔。槽糕,你没有保存画笔句柄,怎么才能删除画笔呢?前面介绍过,SelectObject 函数将返回先前被选入设备环境的画笔句柄。也就是说,可以通过将备用的 BLACK_PEN 选入到设备环境中来得到需要被删除的画笔句柄,然后删除它:

[cpp] view plain copy
  1. DeleteObject (SelectObject (hdc, GetStockObject (BLACK_PEN)));  

        下面给出另一个方法。当将一支画笔选入到一个新创建的设备环境时,保存 SelectObject 返回的画笔句柄:

[cpp] view plain copy
  1. hPen = SelectObject (hdc, CreatePen (PS_DASH, 0, RGB (255, 0, 0)));  
hPen 究竟是什么呢?如果这是在获得设备环境后第一次调用 SelectObject 函数,hPen 就是 BLACK_PEN 的句柄。现在可以在同一条语句中选择该画笔到设备环境,并且删除自己创建的画笔(第二次 SelectObject 调用返回你创建的画笔的句柄):
[cpp] view plain copy
  1. DeleteObject (SelectObject (hdc, hPen));  

        如果有一个画笔的句柄,LOGPEN 结构中各个字段成员的值可以通过调用 GetObject 函数获得:

[cpp] view plain copy
  1. GetObject (hPen, sizeof(LOGPEN), (LPVOID) &logpen);  

        如果需要获得当前被选入设备环境的画笔句柄,则调用:

[cpp] view plain copy
  1. hPen = GetCurrentObject (hdc, OBJ_PEN);  

        我将在第 17 章讨论另外一个画笔创建函数:ExtCreatePen。

5.3.7  填充空隙

        使用点式画笔和虚线画笔会带来这样一个问题:点和虚线之间的空隙是什么颜色呢?你觉得呢?

        空隙的颜色是由设备环境的两个属性(背景模式和背景颜色)决定的。默认的背景模式是 OPAUQE(不透明),这就意味着 Windows 使用背景颜色来填充空隙,背景颜色在默认时是白色。这与许多程序在窗口类中用 WHITE_BRUSH 来擦除窗口背景的做法相同。

        可以通过调用下面的函数来改变 Windows 填充空隙的背景颜色:

[cpp] view plain copy
  1. SetBKColor (hdc, crColor);  
crColor 参数和画笔颜色中使用时一样,Windows 会将背景色转换为纯色。定义在设备环境的当前背景颜色可以通过调用 GetBKColor 函数获得。

        也可以通过将背景模式改为 TRANSPARENT(透明)来阻止 Windows 填充空隙:

[cpp] view plain copy
  1. SetBKMode (hdc, TRANSPARENT);  
这样,Windows 会忽略背景颜色,从而不填充空隙。当前的背景模式可以通过调用 GetBKMode 函数获取(要么是 TRANSPARENT,要么是 OPAQUE)。
0 0
原创粉丝点击