zoukankan      html  css  js  c++  java
  • 第5章 绘图基础_5.6 矩形、区域和剪裁

     5.6.1 处理矩形

    (1)绘图函数

    绘图函数

    说明

    FillRect(hdc,&rect,hBrush)

    不用先将画刷选入设备环境

    FrameRect(hdc,&rect,hBrush)

    绘制边框,不填充(注意是用画刷,而不是画笔)

    InvertRect(hdc,&rect)

    像素反转,由1变0,0变1。

    (2)操纵RECT结构的函数

    操作矩形

    函数

    1、设置RECT字段

    SetRect(&rect,xLeft,yTop,xRight,yBottom);

    2、沿x和y移动几个单位

    OffsetRect(&rect,x,y);

    3、增大或减小矩形

    InflateRect(&rect,x,y);

    4、矩形各字段设为0

    SetRectEmpty(&rect);

    5、复制矩形

    CopyRect(&DestRect,&SrcRect);

    6、获取矩形的交集

    IntersectRect(&DestRect,&SrcRect1,&SrcRect2);

    7、判断矩形是否为空

    bEmpty = IsRectEmpty(&rect);

    8、点是否在矩形内部

    bInRect = PtInRect(&rect,point);

    5.6.2 随机矩形

    (1)GetMessage与PeekMesssage的区别

     

    GetMessage

    PeekMessage

    作用

    获取一条消息,并从消息队列里删掉除该消息(除WM_PAINT外)。

    检查消息队列的消息,是否删除,取决于最后一个参数是PM_REMOVE或PM_NOREMOVE。

    控制权

    获得消息,才返回。

    立即返回,不管是否有消息

    返回值

    获得非WM_QUIT消息时,返回非零

    获得WM_QUIT时,返回0

    TRUE表示有消息,FALSE表示没有消息。

    (2)删除WM_PAINT消息:唯一的方法是使无效区域变成有效。可以用ValidateRect等。

      //以下是错误,如果WM_PAINT在队列中,循环将无法退出。

      while(PeekMessage(&msg,NULL,0,0,PM_REMOVE));

    (3)消息循环另一法表示法

    GetMessage方法

    PeekMessage方法

    while(GetMessage(&msg,NULL,0,0))
    {
         TranslateMessage(&msg);
         DispatchMessage(&msg);
    }
    
    return msg.wParam;
    while(TRUE)
    {   
        //有消息时正常处理
        if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
        {
            //必须检查WM_QUIT消息
            if(msg.message == WM_QUIT) break;
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else //消息队列为空时
        {
            //空闲时,做其他事情
        }
    }
    
    return msg.wParam;
    【RandRect程序】
    /*-----------------------------------------
    RANDRECT.C --
    (c) Charles Petzold, 1998
    -----------------------------------------*/
    #include <windows.h>
    static int cxClient, cyClient;
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    void DrawRectangle(HWND hwnd)
    {
        HBRUSH hBrush;
        HDC hdc;
        RECT rect;
    
        //随机矩形rand()返回0-0x7fff之间的整数
        SetRect(&rect, rand() % cxClient, rand() % cyClient, rand() % cxClient, rand() % cyClient);
        //随机颜色
        hBrush = CreateSolidBrush(RGB(rand() % 256, rand() % 256, rand() % 256));
        //填充
        hdc = GetDC(hwnd);
        FillRect(hdc, &rect, hBrush);
        ReleaseDC(hwnd, hdc);
        DeleteObject(hBrush);
    }
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
        PSTR szCmdLine, int iCmdShow)
    {
        static TCHAR szAppName[] = TEXT("RandRect");
        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("This program requires Windows NT!"),
                szAppName, MB_ICONERROR);
            return 0;
        }
    
        hwnd = CreateWindow(szAppName, TEXT("RandRect"),
            WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT, CW_USEDEFAULT,
            CW_USEDEFAULT, CW_USEDEFAULT,
            NULL, NULL, hInstance, NULL);
    
        ShowWindow(hwnd, iCmdShow);
        UpdateWindow(hwnd);
    
        //用PeekMessage的消息循环
        while (TRUE)
        {
            if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
            {
                if (msg.message == WM_QUIT) break;
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
            else
            {
                DrawRectangle(hwnd);
            }
        }
    
        return msg.wParam;
    }
    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        switch (message)
        {
        case WM_SIZE:
            cxClient = LOWORD(lParam);
            cyClient = HIWORD(lParam);
            return 0;
    
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
        }
        return DefWindowProc(hwnd, message, wParam, lParam);
    }

    5.6.3 矩形与区域的剪裁

    (1)区域可进行绘图或剪裁,是一个GDI对象,得选入设备和DeleteObject。

    (2)创建区域

      ①hRgn =CreateRectRgn(xLeft,yTop,xRight,yBottom); //矩形区域

      ②hRgn =CreateEllispseRgn(xLeft,yTop,xRight,yBottom);//椭圆区域

      ③hRgn =CreatePolygonRgn(&apt,iCount,iPolyFillMode); //多边形区域

    (3)区域的合并iRgnType=CombineRgn(hDestRgn,hSrcRgn1,hSrcRgn2,iCombine)

    参数

    iCombine值

    RGN_AND

    两个源区域公共部分

    RGN_OR

    两个源区域的全部

    RGN_XOR

    两源区域全部,但去除公共部分

    RGN_DIFF

    源1不在源2的部分

    RGN_COPY

    源1全部(忽略源2)

    返回值

    iRgnType

    NULLREGION

    空区域

    SIMPLEREGION

    简单矩形、椭圆或多边形

    COMPLEXREGION

    复杂区域

    ERROR

    有错误发生

    说明:①将两个源区域组合起来,并产生目标句柄,hDestRgn先前的区域将被销毁。

         ②使用函数前,可让hDestRgn在初始时表示一个很小的矩形区域。

    (4)区域绘图函数

    FillRgn(hdc,hRgn,hBrush)

    //与FillRect类似

    FrameRgn(hdc,hRgn,hBrush,xFrame,yFrame)

    //xFrame,yFrame表示区域周围的边框的逻辑宽度和高度

    InvertRgn(hdc,hRgn);

    //与InvertRect类似

    PaintRgn(hdc,hRgn);

    //用当前设备环境的画刷来填充区域

    (5)删除区域:DeleteObject(hRgn); //要删除,因为是GDI对象。

    5.6.4 矩形与区域的剪裁

    (1)无效矩形和无效区域的产生与获取

    无效区产生

    获取

    //无效矩形

    InvalidateRect(hwnd,NULL,TRUE)

    //无效区域(形状不一定是矩形)

    InvalidateRgn(hwnd,hRgn,TRUE)

    BeginPaint(hdc,&ps)或

    GetUpdateRect

    (2)创建自己的剪裁区域

      ①SelectObject(hdc,hRgn);

      ②SelectClipRgn(hdc,hRgn);

    (3)删除剪裁区域:GDI为剪裁区域做了一个副本,因此区域选入设备环境后,可以删除。
    5.6.5 CLOVER程序

    /*------------------------------------------------------------
    
    CLOVER.C -- Clover Drawing Program Using Regions
    (c) Charles Petzold, 1998
    ------------------------------------------------------------*/
    #include <windows.h>
    #include <math.h>
    #define TWO_PI (2.0 * 3.14159)
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
        PSTR szCmdLine, int iCmdShow)
    {
        static TCHAR szAppName[] = TEXT("Clover");
        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("This program requires Windows NT!"),
                szAppName, MB_ICONERROR);
            return 0;
        }
    
        hwnd = CreateWindow(szAppName,                  // window class name
            TEXT("三叶虫图形"), // window caption
            WS_OVERLAPPEDWINDOW,        // window style
            CW_USEDEFAULT,              // initial x position
            CW_USEDEFAULT,              // initial y position
            CW_USEDEFAULT,              // initial x size
            CW_USEDEFAULT,              // initial y size
            NULL,                       // parent window handle
            NULL,                       // window menu handle
            hInstance,                  // program instance handle
            NULL);                     // creation parameters
    
        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)
    {
        HDC          hdc;
        PAINTSTRUCT  ps;
        static int   cxClient, cyClient;
        static HRGN  hRgnClip;
        double       fAngle, fRadius;
        HRGN         hRgnTemp[6];
        switch (message)
        {
        case WM_CREATE:
    
            return 0;
        case WM_SIZE:
            cxClient = LOWORD(lParam);
            cyClient = HIWORD(lParam);
            if (hRgnClip) DeleteObject(hRgnClip);
            //创建椭圆区域
            hRgnTemp[0] = CreateEllipticRgn(0, cyClient / 3, cxClient / 2, 2 * cyClient / 3);             //左椭圆
            hRgnTemp[1] = CreateEllipticRgn(cxClient / 2, cyClient / 3, cxClient, 2 * cyClient / 3);   //右椭圆
            hRgnTemp[2] = CreateEllipticRgn(cxClient / 3, 0, 2 * cxClient / 3, cyClient / 2);             //上椭圆
            hRgnTemp[3] = CreateEllipticRgn(cxClient / 3, cyClient / 2, 2 * cxClient / 3, cyClient);   //下椭圆
            //初始化各合并区域
            hRgnTemp[4] = CreateRectRgn(0, 0, 1, 1);    //1个像素大小的区域
            hRgnTemp[5] = CreateRectRgn(0, 0, 1, 1);
            hRgnClip = CreateRectRgn(0, 0, 1, 1);
            //合并
            CombineRgn(hRgnTemp[4], hRgnTemp[0], hRgnTemp[1], RGN_OR); //合并全部
            CombineRgn(hRgnTemp[5], hRgnTemp[2], hRgnTemp[3], RGN_OR); //合并合部
            CombineRgn(hRgnClip, hRgnTemp[4], hRgnTemp[5], RGN_XOR);   //去除公共部分
            for (int i = 0; i < 6; i++)
            {
                DeleteObject(hRgnTemp[i]);
            }
            return 0;
        case WM_PAINT:
            hdc = BeginPaint(hwnd, &ps);
    
            //将逻辑点(0,0)映射到客户区中央
            SetViewportOrgEx(hdc, cxClient / 2, cyClient / 2, NULL);
            //设置剪裁区域
            SelectClipRgn(hdc, hRgnClip);
            //画射线
            int xPos, yPos;
            fRadius = _hypot(cxClient / 2.0, cyClient / 2.0);//射线长度
            for (fAngle = 0.0; fAngle < TWO_PI; fAngle += TWO_PI / 360)
            {
                MoveToEx(hdc, 0, 0, NULL);
                xPos = (int)(fRadius * cos(fAngle) + 0.5); //加0.5是为了四舍五入取整,如3.5+0.5,取整4。
                yPos = (int)(fRadius * sin(fAngle) + 0.5);
                LineTo(hdc, xPos, yPos);
            }
    
            EndPaint(hwnd, &ps);
            return 0;
    
        case WM_DESTROY:
            if (hRgnClip) DeleteObject(hRgnClip);
            PostQuitMessage(0);
            return 0;
        }
        return DefWindowProc(hwnd, message, wParam, lParam);
    }
     
  • 相关阅读:
    iOS ARC下命名规则
    performSelector may cause a leak because its selector is unknown
    performSelector may cause a leak because its selector is unknown
    Block的Retain Cycle的解决方法
    Block的Retain Cycle的解决方法
    iOS 5 ARC 入门
    iOS 5 ARC 入门
    Xcode 5 SVN配置
    Python基本语法_基本数据类型_序列类型详解
    Python基本语法_基本数据类型_序列类型详解
  • 原文地址:https://www.cnblogs.com/5iedu/p/4656167.html
Copyright © 2011-2022 走看看