区域的创建和选择
一个应用程序通过调用指定形状的函数来创建一个区域。下表显示了创建标准图形的函数
形状 | 函数 |
矩形区域 | 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; }
博客介绍了应用程序中区域的创建和选择,通过调用指定形状函数创建区域并选择进设备内容。还阐述了区域的多种操作,如合并、比较、填充等,以及区域着色、反转、加框架等处理。最后给出使用区域裁减输出的例子,包括定义裁减区域和裁减输出的具体操作。
1609

被折叠的 条评论
为什么被折叠?



