第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);
}
时间: 2024-10-07 03:17:56

第5章 绘图基础_5.6 矩形、区域和剪裁的相关文章

第04章-VTK基础(5)

[译者:这个系列教程是以Kitware公司出版的<VTK User's Guide -11th edition>一书作的中文翻译(出版时间2010年,ISBN: 978-1-930934-23-8),由于时间关系,我们不能保证每周都能更新本书内容,但尽量做到一周更新一篇到两篇内容.敬请期待^_^.欢迎转载,另请转载时注明本文出处,谢谢合作!同时,由于译者水平有限,出错之处在所难免,欢迎指出订正!] [本小节内容对应原书的第63页至第70页] 4.11 文本标注 VTK提供了两种方法用于标注图像

Android中Canvas绘图基础详解(附源码下载)

Android中,如果我们想绘制复杂的自定义View或游戏,我们就需要熟悉绘图API.Android通过Canvas类暴露了很多drawXXX方法,我们可以通过这些方法绘制各种各样的图形.Canvas绘图有三个基本要素:Canvas.绘图坐标系以及Paint.Canvas是画布,我们通过Canvas的各种drawXXX方法将图形绘制到Canvas上面,在drawXXX方法中我们需要传入要绘制的图形的坐标形状,还要传入一个画笔Paint.drawXXX方法以及传入其中的坐标决定了要绘制的图形的形状

【机器学习实战】第1章 机器学习基础

第1章 机器学习基础 机器学习 概述 机器学习就是把无序的数据转换成有用的信息. 获取海量的数据 从海量数据中获取有用的信息 我们会利用计算机来彰显数据背后的真实含义,这才是机器学习的意义. 机器学习 场景 例如:识别动物猫 模式识别(官方标准):人们通过大量的经验,得到结论,从而判断它就是猫. 机器学习(数据学习):人们通过阅读进行学习,观察它会叫.小眼睛.两只耳朵.四条腿.一条尾巴,得到结论,从而判断它就是猫. 深度学习(深入数据):人们通过深入了解它,发现它会'喵喵'的叫.与同类的猫科动物

QT绘图基础(一)

2D绘图 Qt4中的2D绘图部分称为Arthur绘图系统.它由3个类支撑整个框架,QPainter,QPainterDevice和QPainterEngine.QPainter用来执行具体的绘图相关操作如画点,画线,填充,变换,alpha通道等.QPainterDevice是QPainter用来绘图的绘图设备,Qt中有几种预定义的绘图设备,如QWidget,QPixamp,QPrinter等.他们都从QPaintDevice继承.QPaintEngine类提供了不同类型设备的接口,QPaintE

Windows GDI绘图基础知识

一.Windows可以画直线.椭圆线(椭圆圆周上的曲线)和贝塞尔曲线.////////////7 个画线函式是:(1)画直线LineTo    BOOL LineTo(HDC hdc,int nXEnd,int nYEnd);结合MoveToEx函数使用BOOL MoveToEx(HDC hdc,int X,int Y,LPPOINT lpPoint);Point记录了旧的坐标点(先前的当前位置).///注意:GetCurrentPositionEx (hdc, &pt) ;获得当前位置. (2

第04章-VTK基础(6)

[译者:这个系列教程是以Kitware公司出版的<VTK User's Guide -11th edition>一书作的中文翻译(出版时间2010年,ISBN: 978-1-930934-23-8),由于时间关系,我们不能保证每周都能更新本书内容,但尽量做到一周更新一篇到两篇内容.敬请期待^_^.欢迎转载,另请转载时注明本文出处,谢谢合作!同时,由于译者水平有限,出错之处在所难免,欢迎指出订正!] [本小节内容对应原书的第70页至第83页] 4.13 数据变换 在4.6节里的"Ass

机器学习实战之第一章 机器学习基础

第1章 机器学习基础 机器学习 概述 机器学习就是把无序的数据转换成有用的信息. 获取海量的数据 从海量数据中获取有用的信息 我们会利用计算机来彰显数据背后的真实含义,这才是机器学习的意义. 机器学习 场景 例如:识别动物猫 模式识别(官方标准):人们通过大量的经验,得到结论,从而判断它就是猫. 机器学习(数据学习):人们通过阅读进行学习,观察它会叫.小眼睛.两只耳朵.四条腿.一条尾巴,得到结论,从而判断它就是猫. 深度学习(深入数据):人们通过深入了解它,发现它会'喵喵'的叫.与同类的猫科动物

1 、Quartz 2D绘图基础

Quartz 2D绘图 Quartz 2D绘图的核心API是CGContextRef,该API专门用于绘制各种图形. 关注微信公众号:ioscoding ,分享优质iOS编程技术.by:shuju 1.1  Quartz 2D绘图基础:CGContextRef 使用Quartz 2D绘图的关键步骤有两步:获取CGContextRef:调用CGContextRef的方法进行绘图. 不同场景下获取CGContextRef的方式各不相同,下面介绍iOS开发中最常见的场景下如何获取CGContextRe

第04章-VTK基础(7)

[译者:这个系列教程是以Kitware公司出版的<VTK User's Guide -11th edition>一书作的中文翻译(出版时间2010年,ISBN: 978-1-930934-23-8),由于时间关系,我们不能保证每周都能更新本书内容,但尽量做到一周更新一篇到两篇内容.敬请期待^_^.欢迎转载,另请转载时注明本文出处,谢谢合作!同时,由于译者水平有限,出错之处在所难免,欢迎指出订正!] [本小节内容对应原书的第83页至第87页] 4.16 动画 动画是可视化等系统的重要模块: 通过