Windows编程 第八回 绘图课(下)

     书接上回,我们先来看一个例子吧,我们画了一个矩形和一个圆:

         case WM_PAINT:

         HDC hDC;

         PAINTSTRUCT ps;

         hDC=BeginPaint(hwnd,&ps);

         Rectangle(hDC,50,50,200,200);

         Ellipse(hDC,100,100,300,300);

         Ellipse(hDC,400,100,600,300);

         Rectangle(hDC,350,50,500,200);

         EndPaint(hwnd,&ps);

          break;

 

你会感到奇怪,这两个函数画出的图形怎么会相互遮盖呢?或许你猜出了原因了,这两个函数不是单纯地画“边框”,其内部还被白色的背景填充着,让它们可以相互遮挡而不是“透明”的。像前面讲过的RectangleEllipseRoundRectChordPie和本回要讲的PolygonPolyPolygon这些画带边界框的填充图形函数都是这样的。

 

认识画刷

 

Windows中图形是以当前设备描述表选中的画刷来填充的。默认情况下,使用现有的白色画刷,这意味着图形内部将画为白色。Windows预定义了六种现有画刷:WHITE_BRUSHLTGRAY_BRUSHGRAY_BRUSHDKGRAY_BRUSHBLACK_BRUSHNULL_BRUSH (也叫HOLLOW_BRUSH),大家看名字就应该知道它们代表什么颜色了吧。你可以将任何一种现有画刷选入你的设备描述表中,就和你选择一种画笔一样。

 

WindowsHBRUSH定义画刷句柄,可以像这样定义一个画刷句柄变量:

 

HBRUSH hBrush

 

你可以通过调用GetStockObject来取得GRAY_BRUSH的句柄:

 

hBrush = (HBRUSH) GetStockObject (GRAY_BRUSH) ;//这里需要强制类型转换

 

你可以调用SelectObject将它选进设备描述表:

 

SelectObject (hdc, hBrush) ;

 

现在,如果你要用上面的提到的任意一个函数画图,则图形内部将为灰色

 

 

 

如果您想画一个没有边界框的图形,可以将NULL_PEN选进设备描述表:

 

SelectObject (hdc,(HBRUSH) GetStockObject (NULL_PEN)) ;
上一回我曾提到过NULL_PEN有啥用?我估计这可能就是它的一个用途吧。
 

 

如果您想画出图形的边界框,但不填入内部,则将NULL_BRUSH选进设备内容:

 

SelectObject (hdc, (HBRUSH) GetStockobject (NULL_BRUSH) ;
大家看到此,应该想出画不互相遮盖的图形了吧:

           case WM_PAINT:

               HDC hDC;
               PAINTSTRUCT ps;
               hDC=BeginPaint(hwnd,&ps);

 

              SelectObject (hDC, (HBRUSH) GetStockObject (NULL_BRUSH) ;  Rectangle(hDC,50,50,200,200);

 

           Ellipse(hDC,100,100,300,300);

 

 

 

           Ellipse(hDC,400,100,600,300);

 

        Rectangle(hDC,350,50,500,200);

 

              EndPaint(hwnd,&ps);
              break;

 

再认识画刷

 

我们除了可以使用以上的现有画刷,还可以创建自己的画刷,就如同上回我们创建自己的画笔一样。而且过程也是类似的:

 

首先创建逻辑画刷,这里Windows为我们提供了几个函数可供使用;

 

然后使用SelectObject把画刷选进设备描述表

 

绘图函数绘图;

 

最后在释放设备描述表(或者在选择了另一种画刷到设备内容中)之后,就可以调用DeleteObject来删除画刷了。

 

 

 

接着我们就来看一下这几个创建画刷的函数吧。

 

下面是建立逻辑画刷的第一个函数:

 

hBrush = CreateSolidBrush (crColor) ;

 

函数中crColorCOLORREF类型,指定画刷颜色。

 

你还可以使用由水平、垂直或者倾斜的线组成的“影线标记(hatch marks)”来创建画刷,这种风格的画刷对着色条形图的内部和在绘图仪上进行绘图最有用。创建影线画刷的函数为:

 

hBrush = CreateHatchBrush (iHatchStyle, crColor) ;

 

iHatchStyle参数描述影线标记的外观。下图显示了六种可用的影线标记风格。

 


 

 

CreateHatchBrush中的crColor参数是影线的色彩。

 

你还可以使用这个函数创建逻辑画刷:

 

hBrush = CreateBrushIndirect (&logbrush) ;

 

变量logbrush是一个类型为LOGBRUSH(“逻辑画刷”)的结构,该结构的三个字段如表5-4所示,lbStyle字段的值确定了Windows如何解释其它两个字段的值:

 

lbStyle (UINT)

lbColor (COLORREF)

lbHatch (LONG)

BS_SOLID

画刷的色彩

忽略

BS_HOLLOW

忽略

忽略

BS_HATCHED

影线的色彩

影线画刷风格

BS_PATTERN

忽略

位图的句柄

BS_DIBPATTERNPT

忽略

指向DIB的指标

 

 

 

上一回我们用SelectObject将逻辑画笔选进设备描述表,用DeleteObject删除画笔,用GetObject来取得逻辑画笔的信息。对于画刷,同样能使用这三个函数。

 

一旦你取得到了画刷句柄,就可以使用SelectObject将该画刷选进设备描述表:

 

SelectObject (hdc, hBrush) ;

 

然后,你可以使用DeleteObject函数删除所建立的画刷:

 

DeleteObject (hBrush) ;

 

但是,不要删除目前选进设备描述表内的画刷。

 

如果您需要取得画刷的信息,可以调用GetObject

 

GetObject (hBrush, sizeof (LOGBRUSH), (LPVOID) &logbrush) ;

 

其中,logbrush是一个类型为LOGBRUSH的结构。

 

Polygon函数和多边形填充

 

我们好像还有两个函数没有讲,趁我还没有忘记,赶紧把它讲完吧。

 

Polygon函数也是一个画带边界框的填充图形函数,它的调用与Polyline函数相似:

 

Polygon (hdc, apt, iCount) ;
        

 

其中,apt参数是POINT结构的一个数组,iCount是点的数目。如果该数组中的最后一个点与第一个点不同,则Windows将会再加一条线,将最后一个点与第一个点连起来(在Polyline函数中,Windows不会这么做)。

 

PolyPolygon函数如下所示:

 

PolyPolygon (hdc, apt, aiCounts, iPolyCount) ; 

 

该函数绘制多个多边形。最后一个参数给出了所画的多边形的个数。对于每个多边形,aiCounts数组给出了多边形的端点数。apt数组具有全部多边形的所有点。除返回值以外,PolyPolygon在功能上与下面的代码相同:

 

for (i = 0, iAccum = 0 ; i < iPolyCount ; i++)
{
    Polygon (hdc, apt + iAccum, aiCounts[i]) ;
    iAccum += aiCounts[i] ;
}

 

对于PolygonPolyPolygon函数,Windows使用定义在设备描述表中的当前画刷来填充这个带边界的区域。至于填充内部的方式,则取决于多边形填充方式,你可以用SetPolyFillMode函数来设定:

 

SetPolyFillMode (hdc, iMode) ;

 

默认情况下,多边形填入方式是ALTERNATE,但是您可以将它设定为WINDING

 

对于ALTERNATE方式,您可以设想从一个无穷大的封闭区域内部的点画线,只有假想的线穿过了奇数条边界线时,才填充封闭区域,当然若为偶数,则不填充该区域。这就是星的角被填充而中心没被填充的原因。

 

 

 

对于WINDING方式:方法一样,如为奇数,填充该区域;如为偶数则要根据边框线的方向来判断:如果穿过的边框线在不同方向的边框线数目相等,则不填充,如不等,则填充。还是来分析个例子吧,比如要绘制下图,线上的箭头指出了画线的方向。

 

 

 

用这两种方式填充的效果如下图(左侧为ALTERNATE方式,右侧为WINDING方式):

 

 

 

两种方式都会填充三个封闭的L形区域,号码从13。号码为45的两个小内部区域,在ALTERNATE方式下不会被填充。但是,在WINDING方式下,号码为5的区域会被填充,因为从区域内必须穿过两条相同方向的线才能到达图形外部。号码为4的区域不会被填充,因为必须穿过两条方向相反的线。

 

 

 

    经过这两节绘图课后,大家应该对Windows中常用的绘图函数有所了解了,发挥你的想象力,去画一些漂亮的图形吧!

 

posted @ 2012-04-07 22:27  hu_jiacheng  阅读(1120)  评论(0编辑  收藏  举报