区域和裁减区域-Window GDI

原文:http://blog.csdn.net/windcsn/article/details/492436

区域的创建和选择

一个应用程序通过调用指定形状的函数来创建一个区域。下表显示了创建标准图形的函数

形状

函数

矩形区域

CreateRectRgn, CreateRectRgnIndirect, SetRectRgn

圆角的矩形区域

CreateRoundRectRgn

椭圆区域

CreateEllipticRgn, CreateEllipticRgnIndirect

多边形区域

CreatePolygonRgn, CreatePolyPolygonRgn

每个区域创建函数返回一个HANDLE来标示新创建的区域。一个应用程序可以通过调用SelectObject函数并将这个HANDLE作为第二个参数来将一个区域选择进设备内容中。在一个区域被选择进设备内容之后,应用程序可以对其执行各种操作。

区域操作

应用程序能够合并区域、比较区域、着色和返回区域内部、给区域画边框、得到区域的大小和测试光标是否位于区域的范围。

合并区域

应用程序通过调用CombineRgn函数来合并两个区域。使用这个函数,应用程序能够合并两个区域的交集、两个区域除交集之外的区域、两个区域的并集等等。下面5个值定理了区域合并的类型。

意义

RGN_AND

两个区域的交集

RGN_COPY

两个区域的第一个区域作为新的区域

RGN_DIFF

第一个区域的部分减去两个区域的交集

RGN_OR

两个区域的并集

RGN_XOR

两个区域的并集减去两个区域的交集

下面图形显示了5种使用CombineRgn来操作正方形和圆合并的可能结果:

比较区域

应用程序通过调用EqualRgn来比较两个区域来判断他们是否一样。EqualRgn认为如果两个区域在形状和大小上相等就认为他们相等。

填充区域

应用程序可以通过调用FillRgn并提供一个刷子来填充某区域的内部。当程序调用FillRgn时,系统使用特定的设备内容的当前填充模式刷子来填充区域。有良种填充模式:交替的和缠绕的。程序能调用SetPolyFillMode函数来设置一个设备内容的填充模式。应用程序调用GetPolyFillMode函数来得到设备内容的当前填充模式。

下图描述了良种填充模式,一种使用交替模式,另一种使用缠绕模式。

交替模式

在交替模式下,为了判断那些像素需要高亮,执行下面的测试:

1.在区域内部选择一个像素

2.延正X轴方向画一条虚设的光线,从像素开始到无穷远

3.每次光线和边界线相交的,增加一个记数值

系统高亮那些记数值是奇数的像素。

缠绕模式

为了判断缠绕模式下那些像素需要高亮,需要执行下面测试:

1.在画每个边界线的时候判断方向

2.在区域的内部选择一个像素

3.画一条光线,延正X方向,从像素点到无穷远

4.每次光线与边界线在正Y部分正交的时候,增加记数值,如果在Y负方向,减记数值。

所有非0的像素被高亮。

AA

A

B

在交替模式下:

A发出的光线经过了三条边界,那么记数值为3,B经过了两条边界,记数值为2,所以A所在的区域为高亮,B所在的区域不是。

区域着色

应用程序使用当前选进设备内容的刷子来填充区域的内部,刷子通过PaintRgn函数来选择的,这个函数使用当前的多边形填充模式(交替和缠绕)。

反转区域

程序通过调用InvertRgn函数来使区域的颜色反色。在单色的显示设备上,InvertRgn是白色像素变黑,黑色像素变白。在彩色屏幕上,这个反转依赖于产生屏幕颜色的技术类型。

为区域增加框架

应用程序可以调用FrameRgn函数来为区域周围画一个边界,并指定边界的宽度和刷子的模式。

得到区域的矩形范围

应用程序通过调用GetRgnBox函数来得到区域边界矩形的大小。如果区域是规则的,GetRgnBox返回区域的大小;如果区域是椭圆形,函数返回包围在椭圆周围的最小矩形的大小,长边的长度和椭圆的主轴相等,短边和椭圆的次轴相同。如果区域是多边形,GetRgnBox返回最小的包围多边形的矩形。

移动区域

应用程序调用OffsetRgn函数来移动区域。给定的延X和Y轴防线的偏移决定了左右上下移动的逻辑单位。

点击测试区域

应用在区域上执行点击测试来判断当前光标位置的坐标。然后传递这些坐标和区域的HANDLE给PtInRegion函数。光标的坐标可以由多种鼠标操作得到,例如WM_LBUTTONDOWN、WM_LBUTTONUP、WM_RBUTTONDOWN和WM_RBUTTONUP。PtInRegion函数的返回值指出当前光标位置是否在给定的区域内。

使用区域来裁减输出

本节包含一个简单的例子,介绍你怎么样使用区域是用户可以定义这样输出客户区域的一部分。用作这个目的的区域被叫做裁减区域。

本节的例子,用户可以通过程序来抓获整个桌面为一位图,但能保存图象的一部分作为BMP文件。

通过单击Define Clip Region菜单,用户能够通过单击鼠标左键并拖动鼠标来选择一个裁减区域。当用户拖动鼠标的时候,应用程序画一个相对于新裁减区域的矩形。

通过单击Clip菜单,用户能够重画指定矩形边界内的图像独立部分。

本节提供下面的主题:

定义裁减区域

当用户单击Define Clip Region时,系统产生一个WM_COMMAND消息。该消息的wParam参数包含了程序自定义常量IDM_DEFINE,这指出用户选择了菜单,程序通过处理该输出并设置布尔变量fDefineRegion,如下面的代码:

case WM_COMMAND:

switch (wParam)

{

case IDM_DEFINE:

fDefineRegion = TRUE;

break;

在Define Clipping Region之后,用户开始通过鼠标的单击和拖动来画矩形。

当用户按下鼠标左键时,系统产生WM_LBUTTONDOWN消息,lParam参数包含了光标的位置,它对应于裁减区域矩形的左上角。程序处理WM_LBUTTONDOWN消息如下:

// These variables are required for clipping.
static POINT ptUpperLeft;
static POINT ptLowerRight;
static POINT aptRect[5];
static POINT ptTmp;
static POINTS ptsTmp;
static BOOL fDefineRegion;
static BOOL fRegionExists;
static HRGN hrgn;
static RECT rctTmp;
int i;
switch (message)
{
    case WM_LBUTTONDOWN:
        if (fDefineRegion)
        {
        // Retrieve the new upper left corner.
            ptsTmp = MAKEPOINTS(lParam);
            ptUpperLeft.x = (LONG) ptsTmp.x;
            ptUpperLeft.y = (LONG) ptsTmp.y;
        }
        if (fRegionExists)
        {
            // Erase the previous rectangle.
            hdc = GetDC(hwnd);
            SetROP2(hdc, R2_NOTXORPEN);
            if (!Polyline(hdc, (CONST POINT *) aptRect, 5))
                errhandler("Polyline Failed", hwnd);
            ReleaseDC(hwnd, hdc);
            // Clear the rectangle coordinates.
            for (i = 0; i < 4; i++)
            {
                aptRect[i].x = 0;
                aptRect[i].y = 0;
            }
            // Clear the temporary point structure.
            ptTmp.x = 0;
            ptTmp.y = 0;
            // Clear the lower right coordinates.
            ptLowerRight.x = 0;
            ptLowerRight.y = 0;
            // Reset the flag.
            fRegionExists = FALSE;
            fDefineRegion = TRUE;
            // Retrieve the new upper left corner.
            ptsTmp = MAKEPOINTS(lParam);
            ptUpperLeft.x = (LONG) ptsTmp.x;
            ptUpperLeft.y = (LONG) ptsTmp.y;
        }
    break;
}

当用户拖动鼠标的时候,系统产生WM_MOUSEMOVE消息并存储新的光标位置到lParam参数中。每次应用程序接收到WM_MOUSEMOVE消息时,它都删除先前的矩形(如果存在的话)并通过PolyLine函数来画一个新的区域,以矩形的四个角的坐标,程序执行下面的工作。

// These variables are required for clipping.
static POINT ptUpperLeft;
static POINT ptLowerRight;
static POINT aptRect[5];
static POINT ptTmp;
static POINTS ptsTmp;
static BOOL fDefineRegion;
static BOOL fRegionExists;
static HRGN hrgn;
static RECT rctTmp;
int i;
switch (message)
{
    case WM_MOUSEMOVE:
    if (wParam & MK_LBUTTON && fDefineRegion)
    {
        // Get a window DC.
        hdc = GetDC(hwnd);
        if (!SetROP2(hdc, R2_NOTXORPEN))
            errhandler("SetROP2 Failed", hwnd);
        // If previous mouse movement occurred, store the original
        // lower right corner coordinates in a temporary structure.
       //如果先前鼠标移动了,原来较小的右下角坐标到ptLowerRight
        if (ptLowerRight.x)
        {
            ptTmp.x = ptLowerRight.x;
            ptTmp.y = ptLowerRight.y;
        }
        // Get the new coordinates of the clipping region's lower
        // right corner.
        //取得新的右下角的坐标
        ptsTmp = MAKEPOINTS(lParam);
        ptLowerRight.x = (LONG) ptsTmp.x;
        ptLowerRight.y = (LONG) ptsTmp.y;
        // If previous mouse movement occurred, erase the original
        // rectangle.
        //如果鼠标已经移动了,删除原来的矩形
        if (ptTmp.x)
        {
            aptRect[0].x = ptUpperLeft.x;
            aptRect[0].y = ptUpperLeft.y;
            aptRect[1].x = ptTmp.x;
            aptRect[1].y = ptUpperLeft.y;
            aptRect[2].x = ptTmp.x;
            aptRect[2].y = ptTmp.y;
            aptRect[3].x = ptUpperLeft.x;
            aptRect[3].y = ptTmp.y;
            aptRect[4].x = aptRect[0].x;
            aptRect[4].y = aptRect[0].y;
            if (!Polyline(hdc, (CONST POINT *) aptRect, 5))
                errhandler("Polyline Failed", hwnd);
        }
        aptRect[0].x = ptUpperLeft.x;
        aptRect[0].y = ptUpperLeft.y;
        aptRect[1].x = ptLowerRight.x;
        aptRect[1].y = ptUpperLeft.y;
        aptRect[2].x = ptLowerRight.x;
        aptRect[2].y = ptLowerRight.y;
        aptRect[3].x = ptUpperLeft.x;
        aptRect[3].y = ptLowerRight.y;
        aptRect[4].x = aptRect[0].x;
        aptRect[4].y = aptRect[0].y;
        if (!Polyline(hdc, (CONST POINT *) aptRect, 5))
             errhandler("Polyline Failed", hwnd);
        ReleaseDC(hwnd, hdc);
    }
    break;

裁减输出

在用户选择Clip菜单之后,应用程序使用用户创建的裁减区域的矩形坐标,在定义裁减区域后,将它选进程序的设备内容中,程序重画位图,程序执行下面的工作:

// These variables are required for clipping.
static POINT ptUpperLeft;
static POINT ptLowerRight;
static POINT aptRect[5];
static POINT ptTmp;
static POINTS ptsTmp;
static BOOL fDefineRegion;
static BOOL fRegionExists;
static HRGN hrgn;
static RECT rctTmp;
int i;
case WM_COMMAND:
    switch (wParam)
    {
    case IDM_CLIP:
    hdc = GetDC(hwnd);
    // Retrieve the application's client rectangle and paint
// with the default (white) brush.
//得到程序的客户区矩形,并用白刷子填充
    GetClientRect(hwnd, &rctTmp);
    FillRect(hdc, &rctTmp, GetStockObject(WHITE_BRUSH));
// Use the rect coordinates to define a clipping region.
//使用rect的坐标来定义一个裁减区域
    hrgn = CreateRectRgn(aptRect[0].x, aptRect[0].y,
        aptRect[2].x, aptRect[2].y);
    SelectClipRgn(hdc, hrgn);
// Transfer (draw) the bitmap into the clipped rectangle.
//将位图画到裁减矩形中
    BitBlt(hdc,
       0, 0,
       bmp.bmWidth, bmp.bmHeight,
       hdcCompatible,
       0, 0,
       SRCCOPY);
    ReleaseDC(hwnd, hdc);
    break;
    }

区域和裁减区域-Window GDI相关推荐

  1. 裁剪(Clipping)-Window GDI

    裁剪(Clipping)-Window GDI http://blog.csdn.net/windcsn/article/details/492105 裁剪是在一个应用程序的窗口中限制输出区域或路径的 ...

  2. OSPF简单多区域及末梢区域配置

    OSPF简单多区域及末梢区域配置 前言 一.简单实验题 二.简单OSPF配置 1.先配置各个路由端口的基本配置 2.配置OSPF 3.路由表及连通性(以R1为例) 三. 末梢区域配置 1.配置 2.连 ...

  3. HALCON示例程序max_connection.hdev确定分割区域的最大区域数目

    HALCON示例程序max_connection.hdev确定分割区域的最大区域数目 示例程序源码(加注释) read_image (Image, 'monkey') get_system ('max ...

  4. 北大青鸟消防设备类型编码_探测器该如何编码?即报警区域、探测区域的真正用途...

    <火灾自动报警系统设计规范> GB 50116-2013中说到 报警区域是将火灾自动报警系统的警戒范围按防火分区或楼层等划分的单元. 报警区域应根据防火分区或楼层划分:可将一个防火分区或一 ...

  5. vs矩形框边框线显示被选中的区域;_条形码区域解码:Web小工具

    条形码解码首先要做定位,找到条形码在图像中的区域.但是有时候受图像质量影响,算法找寻的区域可能产生偏差,最后导致解码失败.这个时候,可以尝试手动选择区域,来辅助条形码的识别. Web Canvas框选 ...

  6. html 设置打印区域,excel打印区域怎么设置

    无论是excel还是word都是我们日常办公较为常见的,在打印excel的时候,经常需要来设定打印区域,才能更好的打印我们所要的东西,而不是默认去分布,这样容易导致自动分页,内容脱节就不好看了.那么, ...

  7. 07-OSPF区域类型--NSSA区域/完全NSSA区域

    Technorati 标签: CCIE,CCNP,OSPF,NSSA,LSA 特别感谢许名川同学的大力帮助,介绍好的资料给我复习这些相关知识 NSSA区域: NSSA区域允许一些外部路由通告到OSPF ...

  8. OSPF定义的5种区域类型:标准区域、主干区域、存根区域、完全存根区域

    OSPF定义了以下5种区域,不同类型的区域对由自治系统外部传入的路由信息的处理方式不同 标准区域:标准区域可以接收任何链路更新信息和路由汇总信息. 主干区域:主干区域是连接各个区域的传输网络,其他区域 ...

  9. ”excel 无法粘贴信息,原因是复制区域与粘贴区域形状不同“解决方法

    excel 无法粘贴信息,原因是复制区域与粘贴区域形状不同 格式,有无合并单元格,单元格状态右击,把锁定去掉等各种方法都尝试过,还是无法解决问题. 后来在一个帖子里看到一个大神的解答,豁然开朗,试之, ...

最新文章

  1. 为什么说可视化编程是糟糕的想法?
  2. python语言入门pdf-python语言入门
  3. Android Design新特性-NavigationView实现抽屉式
  4. 北京低利用率数据中心将有序关闭腾退
  5. 开箱即用Bumblebee独立部署搭建webapi网关详解
  6. UICollectionView reloadData后cell被隐藏
  7. 中国工程院院士和科学院院士有什么区别,谁贡献很大却没有入院士?
  8. node deno_Deno手册:带有代码示例的TypeScript运行时教程
  9. 输入学号查询课程c语言,广工c语言课程设计
  10. Python类调用实例方法
  11. 在大于32GB或64GB容量的SD卡上使用NOOB安装树莓派 - Using NOOB on SD cards larger than 32GB or 64GB for Raspberry Pi...
  12. html组件做成圆角,css3制作圆角按钮
  13. windows7 旗舰版 集成 usb3.0 NVMe 支持 AM4
  14. 关于电脑突然产生数字文件夹用360删不掉的情况
  15. 用python画蜡笔小新的步骤_蜡笔小新 - python代码库 - 云代码
  16. codeforces1296F Berland Beauty
  17. ios越狱,impactor无法使用的替代方案
  18. vivo Z1i的usb调试模式在哪里,打开vivo Z1iusb调试模式的流程
  19. Java Semaphore实现高并发场景下的流量控制(附源码) | 实用代码架构
  20. 北京东物流,南顺丰速运

热门文章

  1. struts.xml配置文件结构
  2. java数组可扩展_[转载]Java数组扩容算法及Java对它的应用
  3. linux mmu的实现的讲解_Linux中的物理内存管理 [一]
  4. python环境准备_python开发环境准备
  5. python判断ip地址是否合法_python实现判断一个字符串是否是合法IP地址的示例
  6. 力扣【每日温度】leetcode-739.每日温度:单调栈解法
  7. UML图系列——建模和面向对象
  8. Java学习笔记——封装
  9. Java-Web Servlet开发
  10. Spring创建Bean的3种方式