恩,继续.

前天我们说到了使用GDI函数进行绘制图形,已经说完了点和线,今天将其补完.

  1. 使用GDI绘制面
  • 绘制矩形 Rectangle (hdc, xLeft, yTop, xRight, yBottom) ;
  • 绘制椭圆 Ellipse (hdc, xLeft, yTop, xRight, yBottom) ;
  • 绘制圆角矩形 RoundRect (hdc, xLeft, yTop, xRight, yBottom, xCornerEllipse, yCornerEllipse) ;
  • 绘制扇型Pie(hdc,xLeft,xTop,xRight,yBottom,xStart,yStart,xEnd,yEnd);
  • 绘制弓型Chord(hdc,xLeft,yTop,xRight,yBottom,xStart,yStart.xEnd,yEnd);

是否觉得绘制扇型和弓型的参数十分类似?其实其参数都是一样的,仅仅是差别一个以圆心为顶点的三角型而已.这两项参数有些复杂,我来说下.Pie(设备句柄,扇型所在圆的外切矩形左上启始点x,y坐标,扇型所在圆的外切矩形右下终止点x,y坐标,扇型两边的x,y坐标)这里值得注意的是,我们获得的扇形或弓形是从Start点到End点逆时针的区域.当我们想绘制另外一半扇型的时候,可以将Start点和End点交换参数,我们就可以获得另外一部分了.

  1. 使用GDI函数控制绘画风格

就如PS一样,我们应该可以选择自己使用的画笔风格,想想我们就算画地图也是需要有需要虚线,粗线,颜色的呢.而GDI画笔可以由我们来控制这些.默认时,我们的内定设备内容将是BLACK_PEN,它将画出一个象素宽的黑色实线.

WINDOWS本身还支持两种画笔,WHITE_PEN,NULL_PEN,从名字意译应该得知,一个为白色单位象素的画笔,一个为空画笔,即此画笔画出的线条不可见.

当然我们可以自定义自己选择的画笔,首先我们需要将画笔选择进入设备的内容.

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

我们调用这两个函数来创建一个基础的画笔,并且将其装入设备. 这是使用默认画笔的方法,我们自行建立画笔的函数为:

hPen = CreatePen (iPenStyle, iWidth, crColor) ;

其中第一个参数是画笔的风格,我们可以确定画笔是实线还是虚线或是点线,这些是在WINGDI.H的头文件中宏定义好的,我现将这些参数做图如下:

第2个参数是画笔的宽度,第三个参数是画笔的颜色.

如我们先定义三个变量来存放三个风格的画笔句柄:

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) ;

再决定自己到底要选择使用哪一个,我们以选用第2个为例

SelectObject (hdc, hPen2) ;

接下来就是绘制图象的函数了,即上面说的画点,线,面的函数.之后在处理WM_DESTROY期间,可以删除所建立的三种画笔。

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

我们说过,GDI支持在一个密闭的范围内进行填充色彩,这时我们使用的不再是画笔,而是画刷,它负责色彩的填充,和画笔类似的是,它也可以自行设置各种属性,我这里继续拿函数使用来说明.

首先我们要建立画刷

hBrush = CreateSolidBrush (crColor) ;

当然,我们还可以使用由水平、垂直或者倾斜的线组成的“影线标记(hatch marks)”来建立不同风格的画刷.

hBrush = CreateHatchBrush (iHatchStyle, crColor) ;

这里的iHatchStyle依旧是画刷的风格.常用宏定义好的类型有:

说到了这里,我给大家提供一段代码案例:

#include     //包含windows头文件

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) //声明回调函数

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)     //WinMain入口函数
{
     //定义窗口类参数
     static TCHAR szAppName[] = TEXT ("AltWind") ;
     HWND hwnd ;
     MSG msg ;
     WNDCLASS wndclass ;
     wndclass.style = CS_HREDRAW | CS_VREDRAW ;
     wndclass.lpfnWndProc= WndProc ;
     wndclass.cbClsExtra = 0 ;
     wndclass.cbWndExtra = 0 ;
     wndclass.hInstance = hInstance ;
     wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
     wndclass.hCursor = LoadCursor (NULL,IDC_ARROW) ;
     wndclass.hbrBackground= (HBRUSH) GetStockObject(WHITE_BRUSH);
     wndclass.lpszMenuName= NULL ;
     wndclass.lpszClassName= szAppName ;
    //判断是否注册窗口成功,若失败则弹出相应的消息警告框
    if (!RegisterClass (&wndclass))
    {
      MessageBox ( NULL, TEXT ("Program requires Windows NT!"), szAppName, MB_ICONERROR) ;
      return 0 ; 
    }
    //创建窗口
    hwnd = CreateWindow (szAppName, TEXT ("Alternate and Winding Fill Modes"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL) ;
    //显示更新窗口
      ShowWindow (hwnd, iCmdShow) ;
      UpdateWindow (hwnd) ; 
    //消息循环中进行消息处理
    while (GetMessage (&msg, NULL, 0, 0))
    {
        TranslateMessage (&msg) ;
        DispatchMessage (&msg) ;
     }
    return msg.wParam ;
 }
 
//消息回调函数
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
    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 ; /*声明两个变量存放鼠标X,Y坐标.
在下面,我们为这两项赋值时,LOWORD(lParam)代表取lParam的低16位,HIWORD(lParam)代表取lParam的高16位,在lParam中存放的实际就是鼠标的位置,低16位为x坐标,高16位为鼠标y坐标.*/
       HDC hdc ;
       int i ; 
       PAINTSTRUCT ps ;
       POINT apt[10] ;
       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 (i = 0 ; i < 10 ; i++)
             { apt[i].x = cxClient * aptFigure[i].x / 200 ;
                apt[i].y =    cyClient * aptFigure[i].y / 100 ;
             }
             SetPolyFillMode (hdc, ALTERNATE) ;
             Polygon (hdc, apt, 10) ;
             for (i = 0 ; i < 10 ; i++)
             {
               apt[i].x += cxClient / 2 ;
             }
             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) ;
}

最后出来的图形应该是这样的