• 《Windows API每日一练》4.4 绘制填充区域


    本节讲述如何填充由线条构建的封闭区域。当我们初始化一个窗口类时,往往已经指定了窗口的背景色画刷(WHITE_BRUSH),即默认的填充封闭区域背景的画刷。如果我们想更换背景颜色,需要选入其他系统预定义的画刷(BLACK_BRUSH、GRAY_BRUSH、NULL_BRUSH)。我们也可以选择创建并选入自定义的画刷。此外,我们还需要关注与填充背景相关的背景模式(透明模式和非透明模式)、填充模式(ALTERNATE模式和WINDING模式)和绘图模式。

    本节必须掌握的知识点:

            多边形填充模式

            第26练:绘制填充区域

            画刷

    4.4.1 多边形填充模式

    Windows使用当前被选入设备环境的画笔来绘制图形的边框线。边框线使用当前的背 景模式、背景颜色和绘图模式,这与Windows绘制线条一样。我们所学的关于线条的所有 知识都适用于这些图形的边框线。下表列出了 Windows用于绘制带有边框的填充区域的7个函数。

    函数名称

    图形

    Rectangle

    直角矩形

    Ellipse

    椭圆

    RoundRect

    圆角矩形

    Chord

    弓形,由椭圆圆周上的弧和一根弦组成

    Pie

    椭圆上的一个扇形

    Polygon

    多边形

    PolyPolygon

    多个多边形

    表4-2 带有边框的填充区域函数

    Windows使用当前选入设备环境的画刷来填充图形。在默认情况下,使用的是备用对象WHITE_BRUSH,这就意味着使用白色来绘制图形内部。

    Windows定义了 6种备用画刷: WHITE_BRUSH、LTGRAY_BRUSH、GRAY_BRUSH、DKGRAY_BRUSH、BLACK_BRUSH 和NULL_BRUSH(又称为HOLLOW_BRUSH)。和选择备用画笔一样,可以将任何一种备用画刷选入设备环境。Windows定义画刷的句柄为HBRUSH类型,所以要先定义一个画 刷句柄变量:

    HBRUSH hBrush;

    获取GRAY_BRUSH句柄可以通过调用如下的GetStockObject函数实现:

    hBrush = GetStockObject (GRAY_BRUSH);

    然后通过调用SelectObject函数将它选进设备环境:

    SelectObject (hdc, hBrush);

    现在,当绘制上表中的任意图形时,内部都会变成灰色。

    如果要绘制一个不含边框线的图形,则要把NULL_PEN画笔选入设备环境:

    SelectObject (hdc, GetStockObject (NULL_PEN));

    如果只想绘制图形的边框线,而不想填充图形的内部,可以将NULL_BRUSH选入设备环境:

    SelectObject (hdc, GetStockobject (NULL_BRUSH);

    也可以建立自定义的画刷,就像建立自定义的画笔一样。我们将在下一小节中介绍。

    Polygon函数和多边形填充模式

    Polygon函数用于绘制一个多边形形状。以下是Polygon函数的常见原型:

    BOOL Polygon(

        HDC hdc,             // 设备上下文句柄

        const POINT* points,   // 多边形的顶点数组指针

        int count            // 顶点的数量

    );

    Polygon函数用于在设备上下文中绘制一个多边形形状。多边形由一系列顶点构成,通过指定顶点的坐标数组来定义。多边形的绘制遵循顺时针顺序连接顶点的规则。

    举例

    以下是一个示例代码,演示如何使用Polygon函数绘制一个三角形:

    HDC hdc = GetDC(hwnd);  // 获取窗口的设备上下文

    POINT points[3];  // 三角形的顶点数组

    points[0].x = 100; points[0].y = 100;  // 第一个顶点

    points[1].x = 200; points[1].y = 200;  // 第二个顶点

    points[2].x = 300; points[2].y = 100;  // 第三个顶点

    Polygon(hdc, points, 3);  // 绘制三角形

    ReleaseDC(hwnd, hdc);  // 释放设备上下文

    上述代码中,我们创建了一个包含三个顶点的POINT数组,并将顶点的坐标赋值。然后调用Polygon函数传递顶点数组和顶点数量来绘制三角形。

    需要注意的是,绘制的多边形将使用当前设备上下文的绘图属性,如线条颜色、填充模式等。

    PolyPolygon函数的调用形式如下:

    PolyPolygon (hdc, apt, aiCounCs, iPolyCounC);

    这个函数会绘制多个多边形。最后一个参数是绘制的多边形的个数。对每个多边形,数组 aiCounts给出了多边形顶点的个数。数组apt含有全部多边形的所有顶点。除了返回值外, PolyPolygon在功能上等同于下面的代码:

    for (i = 0, iAccum = 0 ; i < iPolyCount ; i++)

    {

           Polygon (hdc, apt + iAccum, aiCounts[i]) ;

           iAccum += aiCounts[i] ;

    }

    对Polygon和PolyPolygon函数,Windows都使用设备环境中的当前画刷来填充区域。 至于内部是如何填充的,要取决于多边形的填充模式,可以调用SetPolyFillMode函数来设置:

    SetPolyFillMode (hdc, iMode);

    在默认情况下,多边形的填充模式是ALTERNATE(交替)但是也可以将它设定为 WINDING(螺旋)。这两种方式的区别如图4-6所示。

    ●ALTERNATE和WINDING模式的区别

    “ALTERNATE” 和 “WINDING”是用来处理复杂路径(即,路径中有交叉或重叠部分)的填充规则,本质上是决定哪些区域是需要被填充,哪些区域是应该被排除的。

    1.ALTERNATE:也称为奇偶规则。该规则通过画直线从需要考虑填充的区域到区域外部,如果这个线穿过路径的交叉点次数是奇数,则算作在路径内部,该区域会被填充,如果是偶数,则不会被填充。

    2.WINDING:也称为非零环绕数规则。按照这个规则,所有的路径都是有方向的。从一个区域向外画射线,路径从左到右穿过射线会加一,从右到左穿过射线会减一,如果最终的结果是非零,那么这个区域视为在路径内部,会被填充。如果结果是零,那么这个区域不会被填充。

    图4-6用两种多边形填充模式绘制的图:ALTERNATE(左)和WINDING(右)

    4.4.2 第26练:绘制填充区域

    /*------------------------------------------------------------------

    026  WIN32 API 每日一练

         第26个例子ALTWIND.C:绘制填充区域

         SetPolyFillMode函数

         Polygon函数

    (c) www.bcdaren.com, 2020

    ----------------------------------------------------------------*/

    #include

    LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

    int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,

     PSTR szCmdLine, int iCmdShow)

    {

         static TCHAR szAppName[] = TEXT ("AltWind.C") ;

        (略)

         return msg.wParam ;

    }

    LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)

    {

         static POINT apt[10];

         //多边形顶点坐标数组

         static POINT aptFigure[10] = { {10,70}, 50,70, 50,10, 90,10, 90,50,

          30,50, 30,90, 70,90, 70,30, 10,30 };

         static int cxClient,cyClient;

         HDC hdc ;

         PAINTSTRUCT ps

         switch (message)

         {

         case WM_SIZE:

              cxClient = LOWORD(lParam);

              cyClient = HIWORD(lParam);

              return 0 ;

         case WM_PAINT :

              hdc = BeginPaint(hwnd,&ps);

              SelectObject(hdc,GetStockObject(GRAY_BRUSH));

              //设置顶点坐标---左图

              for (int i = 0;i < 10;i++)

              {

                   apt[i].x = cxClient *aptFigure[i].x/200;

                   apt[i].y = cyClient *aptFigure[i].y/200;

              }

              //设置ALTERNATE填充模式

              //选择交替模式(填充每条扫描线上奇数和偶数多边形边之间的区域)

              SetPolyFillMode(hdc,ALTERNATE);

              Polygon(hdc,apt,10);//绘制多边形

              //重置顶点坐标---左图

              for (int i = 0;i < 10;i++)

              {

                   apt[i].x += cxClient/2;

              }

              //设置WINDING填充模式

              //选择缠绕模式(用非零缠绕值填充任何区域)

              SetPolyFillMode(hdc,WINDING);

              Polygon(hdc,apt,10);//绘制多边形

              EndPaint(hwnd,&ps);

              return 0;

         case WM_DESTROY:

              PostQuitMessage(0);

              return 0;

         }

         return DefWindowProc(hwnd, message, wParam, lParam);

    }

    /******************************************************************************

    SetPolyFillMode函数:设置填补多边形多边形填充模式。

    int SetPolyFillMode(

      HDC hdc,

      int mode     //ALTERNATE:选择替代模式,只有该射线穿越奇数条边框线时,封闭区域才会被填充。

                   //WINDING:选择绕线模式,穿过奇数条边框线或相同方向偶数条边时封闭区域才会被填充。

    );

    *******************************************************************************

    Polygon函数:

    绘制由以直线连接两个或更多个顶点的多边形。

    使用当前的笔勾勒出多边形的轮廓,并使用当前的笔刷和多边形填充模式填充多边形。

    BOOL Polygon(

      HDC         hdc,

      const POINT *apt, //指向POINT结构数组的指针,该数组以逻辑坐标形式指定多边形的顶点。

      int         cpt   //数组中的顶点数。该值必须大于或等于2。

    );

    */

    运行结果:

    图4-7 填充模式

           总结

           上述实例非常简单,窗口过程中处理WM_PAINT消息时,先调用SelectObject函数选入一个灰色背景画刷,然后使用一个for循环语句初始化一个多边形顶点坐标数组,接着调用SetPolyFillMode函数和SetPolyFillMode函数设置填充模式并绘制多边形。

    4.4.3 画刷

           在4.3节中我们讲述了如何创建新的自定义画笔。同样的道理,我们也可以创建新的自定义画刷。

    Windows允许使用5种函数来建立逻辑画刷。调用SelectObject函数将画刷选入设备 环境。逻辑画刷也是GDI对象,这和逻辑画笔一样。所以所有你建立的画刷都必须最终被删除,但是如果它当前被选入了设备环境中,则不要删除它。

    建立逻辑画刷的第一个函数

    hBrush = CreateSolidBrush (crColor);

    这个函数中的Solid(中文含义为实心)并不意味着画刷为纯色。将该画刷选入设备环境后, Windows可能会建立一个抖动位图,并且使用它作为画刷。

    建立逻辑画刷的第二个函数

    可以使用由水平、垂直或者对角线组成的“阴影线标记”(hatchmark)来建立一个画刷。这种样式的画刷对着色条形图的内部和在绘图机上绘图最常用。建立阴影线画刷的函数如下:

    hBrush = CreateHatchBrush (iHatchSCyle, crColor);

    参数iHatchStyle表示阴影线标记的外观。图4-8显示了 6种可用的明影线样式及其外观。

                                              图4-8 6种阴影线固刷样式

                               

    CreateHatchBrush函数中的参数crClolor表示阴影线的颜色。把画刷选入设备环境后, Windows把这种颜色转换为显示器上可用的最近的纯色。阴影线之间的区域会使用设备环 境中定义的背景模式和背景颜色来着色。如果背景模式是OPAQUE,则背景颜色(也被转换 为纯色)用来填充线与线之间的空隙。如果背景的模式是TRANSPARENT,则Windows只画出阴影线,不填充它们之间的空隙。

    建立逻辑画刷的第三和第四个函数

    可以通过函数CreatePatternBrush和CreateDIBPatternBrushPt来建立自己的位图画刷。我们将在第十四章位图详细讲解。

    建立逻辑画刷的第五个函数

    建立逻辑画刷的第5个函数包含其他4个函数的所有功能:

    hBrush = CreateBrushlndirect (&logbrush);

    变量logbrush是一个类型为LOGBRUSH( “逻辑画刷”)的结构。这个结构有三个字段,lbStyle字段的值决定着Windows如何解释其他的两个字段。

    LOGBRUSH结构体(三个字段,lbStyle 字段的值决定Windows如何解释其他两个字段)

    lbStyle(UINT)

    lbColor(COLORREF)

    lbHatch(LONG)

    BS_SOLID

    画刷的颜色

    被忽略

    BS_HOLLOW

    被忽略

    被忽略

    BS_HATCHED

    阴影线的颜色

    阴影线画刷的样式

    BS_PATTERN

    被忽略

    位图的句柄

    BS_DIBPATTERNPT

    被忽略

    指向DIB的指针

    选入画刷和删除画刷

    画刷作为GDI对象,同样必须遵循GDI对象三原则。在前面我们调用SelectObject函数将逻辑画笔选入设备环境,调用DeleteObject函数来 删除这个逻辑画笔,调用GetObject函数来获取逻辑画笔的信息。对于画刷,同样可以使用 这三个函数。一旦拥有一个画刷句柄,就可以调用SelectObject函数将其选入设备环境:

    SelectObject (hdc, hBrush);

    然后,调用DeleteObject函数删除已建立的画刷:

    DeleteObject (hBrush);

    但是不要删除当前被选入设备环境的画刷。

    如果需要获取画刷的信息,可以调用GetObject函数:

    GetObject (hBrush, sizeof (logbrush), (LPVOID) slogbrush);

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

  • 相关阅读:
    DS18B20数字温度计 (一) 电气特性, 寄生供电模式和远距离接线
    vscode语音插件开发-在nodejs里面转换音频文件格式并压缩导出zip格式
    java刷题day 06
    C/C++ 进程间通信system V IPC对象超详细讲解(系统性学习day9)
    四、伊森商城 前端基础-Vue MVVM思想&Vue安装&单向绑定 p21
    c语言tips-宏连接
    HyperBDR新版本上线,自动化容灾兼容再升级!
    【面试经典150 | 区间】合并区间
    配置OSPF包文分析和验证
    slf4j中如何进行log4j配置呢?
  • 原文地址:https://blog.csdn.net/bcdaren/article/details/139730349