使用画笔 Stock Pens

Windows使用设备内容中目前选中的「画笔」来画线。画笔决定线的色彩、宽度和画笔样式,画笔样式可以是实线、点划线或者虚线,内定设备内容中画笔为BLACK_PEN。不管映像方式是什么,这种画笔都画出一个图素宽的黑色实线来。BLACK_PEN是Windows提供的三种现有画笔之一,其它两种是WHITE_PEN和NULL_PEN,NULL_PEN什么都不画。

Windows程序以句柄来使用画笔。 Windows表头文件WINDEF.H中包含一个叫做HPEN的型态定义,即画笔的句柄,可以定义这个型态的变量(例如hPen):

HPEN hPen ;

呼叫GetStockObject,可以获得现有画笔的句柄。例如,假设您想使用名为WHITE_PEN的现有画笔,可以如下取得画笔的句柄:

hPen = GetStockObject (WHITE_PEN) ;

现在必须将画笔选进设备内容:

SelectObject (hdc, hPen) ;

也可以不定义hPen变量,而将GetStockObject和SelectObject呼叫合并成一个叙述:

SelectObject (hdc, GetStockObject (WHITE_PEN)) ;

如果想恢复到使用BLACK_PEN的状态,可以用一个叙述取得这种画笔的句柄,并将其选进设备内容:

SelectObject (hdc, GetStockObject (BLACK_PEN)) ;

SelectObject的传回值是此呼叫前设备内容中的画笔句柄。如果启动一个新的设备内容并呼叫

hPen = SelectObject (hdc, GetStockobject (WHITE_PEN)) ;

则设备内容中的目前画笔将为WHITE_PEN,变量hPen将会是BLACK_PEN的句柄。以后通过呼叫

SelectObject (hdc, hPen) ;

就能够将BLACK_PEN选进设备内容。

画笔的建立、选择和删除

尽管使用现有画笔非常方便,但却受限于实心的黑画笔、实心的白画笔或者没有画笔这三种情况。如果想得到更丰富多彩的效果,就必须建立自己的画笔。

这一过程通常是:使用函数CreatePen或CreatePenIndirect建立一个「逻辑画笔」,这仅仅是对画笔的描述。这些函数传回逻辑画笔的句柄;然后,呼叫SelectObject将画笔选进设备内容。现在,就可以使用新的画笔来画线了。在任何时候,都只能有一种画笔选进设备内容。在释放设备内容(或者在选择了另一种画笔到设备内容中)之后,就可以呼叫DeleteObject来删除所建立的逻辑画笔了。在删除后,该画笔的句柄就不再有效了。

逻辑画笔是一种「GDI对象」,它是您可以建立的六种GDI对象之一,其它五种是画刷、位图、区域、字体和调色盘。除了调色盘之外,这些对象都是通过SelectObject选进设备内容的。

在使用画笔等GDI对象时,应该遵守以下三条规则:

  • 最后要删除自己建立的所有GDI对象。
     
  • 当GDI对象正在一个有效的设备内容中使用时,不要删除它。
     
  • 不要删除现有对象。
     

这些规则当然是有道理的,而且有时这道理还挺微妙的。下面我们将举些例子来帮助理解这些规则。

CreatePen函数的语法形如:

hPen = CreatePen (iPenStyle, iWidth, crColor) ;

其中,iPenStyle参数确定画笔是实线、点线还是虚线,该参数可以是WINGDI.H表头文件中定义的以下标识符

对于PS_SOLID、PS_NULL和PS_INSIDEFRAME画笔样式,iWidth参数是画笔的宽度。iWidth值为0则意味着画笔宽度为一个图素。现有画笔是一个图素宽。如果指定的是点划线或者虚线式画笔样式,同时又指定一个大于1的实际宽度,那么Windows将使用实线画笔来代替。

CreatePen的crColor参数是一个COLORREF值,它指定画笔的颜色。对于除了PS_INSIDEFRAME之外的画笔样式,如果将画笔选入设备内容中,Windows会将颜色转换为设备所能表示的最相近的纯色。PS_INSIDEFRAME是唯一一种可以使用混色的画笔样式,并且只有在宽度大于1的情况下才如此

也可以通过建立一个型态为LOGPEN(「逻辑画笔」)的结构,并呼叫CreatePenIndirect来建立画笔。如果您的程序使用许多能在原始码中初始化的画笔,那么使用这种方法将有效得多。

LOGPEN logpen ;

此结构有三个成员:lopnStyle(无正负号整数或UINT)是画笔样式,lopnWidth(POINT结构)是按逻辑单位度量的画笔宽度,lopnColor (COLORREF)是画笔颜色。Windows只使用lopnWidth结构的x值作为画笔宽度,而忽略y值。

将结构的地址传递给CreatePenIndirect结构就可以建立画笔了:

hPen = CreatePenIndirect (&logpen) ;

注意,CreatePen和CreatePenIndirect函数不需要设备内容句柄作为参数。这些函数建立与设备内容没有联系的逻辑画笔。直到呼叫SelectObject之后,画笔才与设备内容发生联系。因此,可以对不同的设备(如屏幕和打印机)使用相同的逻辑画笔。

面是建立、选择和删除画笔的一种方法。假设您的程序使用三种画笔-一种宽度为1的黑画笔、一种宽度为3的红画笔和一种黑色点式画笔,您可以先定义三个变量来存放这些画笔的句柄:

static HPEN hPen1, hPen2, hPen3 ;

在处理WM_CREATE期间,您可以建立这三种画笔:

hPen1 = CreatePen (PS_SOLID, 1, 0) ;
        
hPen2 = CreatePen (PS_SOLID, 3, RGB (255, 0, 0)) ;
        
hPen3 = CreatePen (PS_DOT, 0, 0) ;

在处理WM_PAINT期间,或者是在拥有一个设备内容有效句柄的任何时间里,您都可以将这三个画笔之一选进设备内容并用它来画线:

SelectObject (hdc, hPen2) ;

在处理WM_DESTROY期间,您可以删除您建立的三种画笔:

DeleteObject (hPen1) ;
        
DeleteObject (hPen2) ;
        
DeleteObject (hPen3) ;

这是建立、选择和删除画笔最直接的方法。但是您的程序必须知道执行期间需要哪些逻辑画笔,为此,您可能想要在每个WM_PAINT消息处理期间建立画笔,并在呼叫EndPaint之后删除它们(可以在呼叫EndPaint之前删除它们,但是要小心,不要删除设备内容中目前选择的画笔)。

你可能还希望随时建立画笔,并将CreatePen和SelectObject呼叫组合到同一个叙述中:

SelectObject (hdc, CreatePen (PS_DASH, 0, RGB (255, 0, 0))) ;

现在再开始画线,您将使用一个红色虚线画笔。在画完红色虚线之后,可以删除画笔。糟了!由于没有保存画笔句柄,怎么才能删除这些画笔呢?不要紧,请记住,SelectObject将传回设备内容中上一次选择的画笔句柄。所以,您可以通过呼叫SelectObject将BLACK_PEN选进设备内容,并删除从SelectObject传回的值

DeleteObject (SelectObject (hdc, GetStockObject (BLACK_PEN))) ;

下面是另一种方法,在将新建立的画笔选进设备内容时,保存SelectObject传回的画笔句柄:

hPen = SelectObject (hdc, CreatePen (PS_DASH, 0, RGB (255, 0, 0))) ;

现在hPen是什么呢?如果这是在取得设备内容之后第一次呼叫SelectObject,则hPen是BLACK_PEN对象的句柄。现在,可以将hPen选进设备内容,并删除所建立的画笔(第二次SelectObject呼叫传回的句柄),只要一道叙述即可:

DeleteObject (SelectObject (hdc, hPen)) ;

如果需要目前选进设备内容的画笔句柄,可以呼叫:

hPen = GetCurrentObject (hdc, OBJ_PEN) ;

如果有一个画笔的句柄,就可以通过呼叫GetObject取得LOGPEN结构各个成员的值:

GetObject (hPen, sizeof (LOGPEN), (LPVOID) &logpen) ;

填入空隙

使用点式画笔和虚线画笔会产生一个有趣的问题:点和虚线之间的空隙会怎样呢?

空隙的着色取决于设备内容的两个属性-背景模式和背景颜色。内定背景模式为OPAQUE,在这种方式下,Windows使用背景色来填入空隙,内定的背景色为白色。这与许多程序在窗口类别中用WHITE_BRUSH来擦除窗口背景的做法是一致的。

可以通过如下呼叫来改变Windows用来填入空隙的背景色:

SetBkColor (hdc, crColor) ;

与画笔色彩所使用的crColor参数一样,Windows将这里的背景色转换为纯色。可以通过用GetBkColor来取得设备内容中定义的目前背景色。

通过将背景模式转换为TRANSPARENT,可以阻止Windows填入空隙:

SetBkMode (hdc, TRANSPARENT);

此后,Windows将忽略背景色,并且不填入空隙,可以通过呼叫GetBkMode来取得目前背景模式(TRANSPARENT或者OPAQUE)。

绘图方式

设备内容中定义的绘图方式也影响显示器上所画线的外观。设想画这样一条直线,它的色彩由画笔色彩和画线区域原来的色彩共同决定。

当Windows使用画笔来画线时,它实际上执行画笔图素与目标位置处原来图素之间的某种位布尔运算。图素间的位布尔运算叫做「位映像运算」,简称为「ROP」。由于画一条直线只涉及两种图素(画笔和目标),因此这种布尔运算又称为「二元位映像运算」,简记为「ROP2」。Windows定义了16种ROP2代码,表示Windows组合画笔图素和目标图素的方式。在内定设备内容中,绘图方式定义为R2_COPYPEN,这意味着Windows只是将画笔图素复制到目标图素,这也是我们通常所熟知的。此外,还有15种ROP2码。

画笔在目标上绘制后会得到什么呢?一种可能是不管画笔和目标的色彩,画出的线总是黑色的,这种绘图方式由ROP2代码R2_BLACK表示。另一种可能是只有当画笔与目标都为黑色时,画出的结果才是白色,其它情况下画出的都是黑色。尽管这似乎有些奇怪,Windows还是为这种方式起了一个名字,叫做R2_NOTMERGEPEN。Windows执行目标图素与画笔图素的位「或」运算,然后翻转所得色彩。

表中指示了画笔色彩(P)与目标色彩(D)是如何组合而成结果色彩的。在标有「布尔操作」的那一栏中,用C语言的表示法给出了目标图素与画笔图素的组合方式。

以通过以下呼叫在设备内容中设定新的绘图模式:

SetROP2 (hdc, iDrawMode) ;

iDrawMode参数是表中「绘图模式」一栏中给出的值之一。您可以用函数:

iDrawMode = GetROP2 (hdc) ;

来取得目前绘图方式。设备内容中的内定设定为R2_COPYPEN,它用画笔色彩替代目标色彩。在R2_NOTCOPYPEN方式下,若画笔为黑色,则画成白色;若画笔为白色,则画成黑色。R2_BLACK方式下,不管画笔和背景色为何种色彩,总是画成黑色。与此相反,R2_WHITE方式下总是画成白色。R2_NOP方式就是「不操作」,让目标保持不变。

我们已经讨论了单色系统。然而,大多数系统是彩色的。在彩色系统中,Windows为画笔和目标图素的每个颜色位执行绘图方式的位运算,并再次使用上表描述的16种ROP2代码。R2_NOT绘图方式总是翻转目标色彩来决定线的颜色,而不管画笔的色彩是什么。例如,在青色目标上的线会变成紫色。R2_NOT方式总是产生可见的画笔,除非画笔在中等灰度的背景上绘图。

发布了25 篇原创文章 · 获赞 8 · 访问量 419

猜你喜欢

转载自blog.csdn.net/cix1314/article/details/103638652
今日推荐