GDI+学习及代码总结之------区域

在GDI+中,对于区域的部分基本上使用了GDI的区域构造函数与合并方法,所以我们先看看GDI中的区域是如何构造与操作的。

GDI中区域构建与操作

一、基本函数

创建矩形区域:

[cpp]  view plain copy
  1. HRGN CreateRectRgnIndirect(CONST RECT *lprc);  
  2. HRGN CreateRectRgn(  
  3.                    int nLeftRect,   // left点坐标(X)  
  4.                    int nTopRect,    //top点坐标值(Y)  
  5.                    int nRightRect,  //right点坐标值(X)  
  6.                    int nBottomRect  //bottom点坐标值(Y)  
  7.                    );  
创建椭圆区域:

[cpp]  view plain copy
  1. HRGN CreateEllipticRgnIndirect(  
  2.                                CONST RECT *lprc   // bounding rectangle  
  3.                                );  
  4. HRGN CreateEllipticRgn(  
  5.                        int nLeftRect,   // x-coord of upper-left corner of rectangle  
  6.                        int nTopRect,    // y-coord of upper-left corner of rectangle  
  7.                        int nRightRect,  // x-coord of lower-right corner of rectangle  
  8.                        int nBottomRect  // y-coord of lower-right corner of rectangle  
  9.                        );  
创建多边形区域:

[cpp]  view plain copy
  1. HRGN CreatePolygonRgn(  
  2.                       CONST POINT *lppt,  // array of points  
  3.                       int cPoints,        // number of points in array  
  4.                       int fnPolyFillMode  // polygon-filling mode  
  5.                       );  
合并区域:

[cpp]  view plain copy
  1. int CombineRgn(  
  2.   HRGN hrgnDest,      // handle to destination region  
  3.   HRGN hrgnSrc1,      // handle to source region  
  4.   HRGN hrgnSrc2,      // handle to source region  
  5.   int fnCombineMode   // region combining mode  
  6. );  
对于CombinMode有四个取值:
RGN_COPY:原样复制hrgnSrc1中的区域,一般不用这个,没太大意义;
RGN_AND:合成的区域是hrgnSrc1和hrgnSrc2的重叠部分;
RGN_DIFF:合成的区域是hrgnSrc1中不包含hrgnSrc2的部分;
RGN_OR:合成的区域同时包含hrgnSrc2和hrgnSrc2;
RGN_XOR:合成的区域同时包含hrgnSrc2和hrgnSrc2,但不包含hrgnSrc2和hrgnSrc2的重叠部分;

区域的句柄可用的4个绘图函数:

[cpp]  view plain copy
  1. FillRgn(hdc, hRgn, hBrush);// 类似FillRect  
  2. FrameRgn(hdc, hRgn, hBrush, xFrame, yFrame);// 类似FrameRect  
  3. InverRgn(hdc, hRgn); //类似InvertRect  
  4. PaintRgn(hdc, hRgn);// 用设备描述表中的当前画刷填充所指的区域。  
所有这些函数都假设区域是逻辑坐标定义的
删除一个区域
[cpp]  view plain copy
  1. DeleteObject(hRgn);  
  2. //Windows的2个作用于区域而不是矩形的函数  
  3. InvalidateRgn(hwnd, hRgn, bErase); //类似于InvalidateRect  
  4. ValidateRgn(hwnd, hRgn); //类似于ValidateRect  
上面两个函数也会以WM_PAINT消息作出反应
剪裁区域
首先是创建剪裁区域
[cpp]  view plain copy
  1. SelectObject(hdc, hRgn);  
  2. SelectClipRgn(hdc, hRgn);  
上面两个函数都是将一个区域选进设备描述表来创建自己的剪裁区域,这个剪裁区域使用设备坐标。
对剪裁区域的操作函数:
[cpp]  view plain copy
  1. ExcludeClipRect 用于将一个矩形从剪裁区域里排除掉  
  2. IntersectClipRect 用于创建一个新的剪裁区域,他是前一个剪裁区域与一个矩形的交集  
  3. OffsetClipRgn 用于将剪裁区域移动到客户区的另一部分  
注意:
GDI会为剪裁区域创建一个副本,所以在将新创建的区域选进设备描述表后,用户可以删除这个区域。
CombineRgn(hDestRgn, hSrcRgn1, hSrcRgn2, iCombine); 中使用的3个区域句柄必须都是有效的,即都要是创建了的。
在调用CombineRgn函数后,源区域即可以删除了,删除不会影响新合成的区域 

看在GDI中使用区域函数的一个示例:(区域抠图)

原理:先用图片大小的矩形构造一个目的区域,所以这个区域的大小就是整个图片的大小,然后从图片的左上角(0,0)开始,按照从上到下、从左到右的顺序形成长宽都为1的矩形(就是一个像素大小),如果矩形中的背景是白色,将之从目的区域中去除,所以最终剩下的区域就是主画面的区域了。这就是“抠”出主界面区域的关键思路所在。

先看下原来的图片:

先看下原来的图片:

抠图代码:

[cpp]  view plain copy
  1. Bitmap photo(L"wlh.bmp");  
  2. //得到相框尺寸  
  3. INT iWidth=photo.GetWidth();  
  4. INT iHeight=photo.GetHeight();  
  5.   
  6. graphics.DrawImage(&photo,0,0,iWidth,iHeight);  
  7. //将绘图平面右移,设置新的绘图原点  
  8. graphics.TranslateTransform(iWidth+10,0);  
  9.   
  10. Color color,colorTemp;  
  11. HRGN endRgn=CreateRectRgn(0,0,iWidth,iHeight);  
  12. //依次获取相框的每一个相素  
  13. for(int iRow=0;iRow<iHeight;iRow++){  
  14.     for(int iColumn=0;iColumn<iWidth;iColumn++){  
  15.         photo.GetPixel(iColumn,iRow,&color);  
  16.         //如果像素为白色,从原有区域中去除当前区域点  
  17.         if(color.GetR()==255&&color.GetG()==255&&color.GetB()==255){  
  18.             HRGN tempRgn=CreateRectRgn(iColumn,iRow,iColumn+1,iRow+1);  
  19.             CombineRgn(endRgn,tempRgn,endRgn,RGN_XOR);  
  20.         }//if--end  
  21.     }  
  22. }  
  23. //创建GDI+区域变量  
  24. Region fillrgn(endRgn);  
  25. graphics.FillRegion(&SolidBrush(Color::Green),&fillrgn);  


GDI+中的区域构建与操作

一、构造函数(Region):

[cpp]  view plain copy
  1. Region()   
  2. Region(path) //从路径构建  
  3. Region(hRgn) //从GDI中的HRGN句柄构建  
  4. Region(Rect& rect) //从矩形构建  
  5. Region(RectF& rect)   
  6. Region(regionData, size) //使用区域数组信息创建  
这里有两个非常重要的构建函数,要说明一下:

[cpp]  view plain copy
  1. Region(hRgn) //从GDI中的HRGN句柄构建  
  2. Region(Rect& rect) //从矩形构建  
对于Region(hRgn):我们很多时候,可以用GDI中区域函数构建区域;然后使用这个构建函数,构建Regin变量,然后使用GDI+中的函数fillRegion啥啥的;
对于Region(Rect):Region类只提供了这么一个矩形构造函数,没有GDI中的椭圆、多边形区域的构建方法,所以当我们构建椭圆、多边形区域时,就是使用GDI了。

二、区域操作(构建区域)

对于GDI中的操作,我们知道CombineRgn的最后一个参数,可以实现对区域的RGN_AND、RGN_DIFF、RGN_OR、RGN_XOR

在GDI+中,Regin类中,也有对区域的操作函数,同样实现了GDI中的区域操作功能,它们分别是:

[cpp]  view plain copy
  1. Region::Intersect(region)//求区域A和区域B的共有部分(交集)  
  2. Region::Union(region)//求同时包含区域A和区域B的区域(并集)  
  3. Region::Xor(region)//求不包含区域A和区域B相交部分的区域(异并集,又称为对称差)  
  4. Region::Complement(region)//求区域B中不含区域A的区域(A的补集)  
  5. Region::Exclude(region)//求区域A中不含区域B的区域(B的补集)  
  6. //异并集(集合的对称差):设A、B为任意两个集合,A和B的对称差为集合S,其元素或属于A,或属于B,但不能即属于A又属于B,这样的集合S称为集合A与B的对称差  

简单的看一个示例吧,(异并集的)

[cpp]  view plain copy
  1. Region rgn1(RectF(25,10,50,100));  
  2. Region rgn2(RectF(0,50,100,30));  
  3.   
  4. Pen pen1(Color::Red,2);  
  5. Pen pen2(Color::Blue,2);  
  6. SolidBrush brush(Color::Green);  
  7.   
  8. rgn1.Xor(&rgn2);  
  9. graphics.TranslateTransform(20,0);//转变绘制原点,这里这句并不是必须的,我只是为了让大家记住这个函数  
  10. graphics.FillRegion(&brush,&rgn1);  
  11. graphics.DrawRectangle(&pen1,RectF(25,10,50,100));  
  12. graphics.DrawRectangle(&pen2,RectF(0,50,100,30));  

三、用矩形表示区域

对于特定的区域,我们都可以使用多个矩形来表示其大致形状。事实上,如果矩形足够小,一定数量的矩形就能够精确表示区域的形状,也就是说,一定数量的矩形所合成的形状,也可以代表区域的形状。Region类的GetRegionScans函数,实现了获取组成区域的矩形集的功能,其调用格式如下:

[cpp]  view plain copy
  1. GetRegionScans(Matrix* matrix, Rect* rects, INT* count)   
  2. GetRegionScans(Matrix* matrix, RectF* rects, INT* count)   
参数:
matrix:[in]绘制平面上的坐标变换矩阵
rects:[out]代表矩形集的数组
count:[out]矩形集的数量,该值可以通过GetRegionScansCount函数获取。

示例:

[cpp]  view plain copy
  1. SolidBrush solidBrush(Color::Red);  
  2. Pen pen(Color::Green);  
  3. GraphicsPath path;  
  4. Matrix matrix;  
  5. Rect *rects=NULL;  
  6. INT count=0;  
  7.   
  8. path.AddEllipse(10,0,80,120);  
  9. Region patchRegion(&path);  
  10. graphics.FillRegion(&solidBrush,&patchRegion);  
  11.   
  12. graphics.GetTransform(&matrix);  
  13. count=patchRegion.GetRegionScansCount(&matrix);  
  14. //为矩形集分配空间  
  15. rects=(Rect*)malloc(count*sizeof(Rect));  
  16.   
  17. patchRegion.GetRegionScans(&matrix,rects,&count);  
  18. graphics.TranslateTransform(140,0);  
  19. for(INT j=0;j<count;j++){  
  20.     graphics.DrawRectangle(&pen,rects[j]);  
  21. }  
  22. free(rects);  

四、击中测试区域(判断点是否在区域内)

击中测试(HitTest),简单地说就是判断一个点是否位于指定的区域内。Region类的成员函数IsVisible提供了这样一个功能。而且还提供了扩展:不仅可以测试一个点是否位于指定的区域中,还可以测试两矩形区域是存否在交集。IsVisible的调用格式为:

[cpp]  view plain copy
  1. IsVisible(Point& point, Graphics* g)   
  2. IsVisible(PointF& point, Graphics* g)   
  3. IsVisible(Rect& rect, Graphics* g)   
  4. IsVisible(RectF& rect, Graphics* g)   
  5. IsVisible(INT x, INT y, Graphics* g)   
  6. IsVisible(REAL x, REAL y, Graphics* g)   
  7. IsVisible(INT x, INT y, INT width, INT height, Graphics* g)   
  8. IsVisible(REAL x, REAL y, REAL width, REAL height, Graphics* g)   
参数说明:
g:[in]绘图平面;
point:[in]点坐标;
rect及x,y,width,height:[in]定义欲测试的矩形区间;

示例:
考虑这样一个应用,当鼠标移动到指定区域时,输出字符串“yes”,否则擦掉这个字符串(擦除操作是用填充背景颜色完成的);

在View类中的OnMouseMove(UINT nFlags, CPoint point)添加如下代码:

[cpp]  view plain copy
  1. Graphics graphics(this->GetDC()->m_hDC);  
  2.   
  3. FontFamily ff(L"Arial");  
  4. Font font(&ff,15,FontStyleRegular,UnitPixel);  
  5.   
  6. Region rgn(RectF(10,10,100,200));  
  7. bool binrgn=rgn.IsVisible(point.x,point.y,&graphics);  
  8. graphics.DrawRectangle(&Pen(Color::Green,2),RectF(10,10,100,200));  
  9. if(binrgn){  
  10.     graphics.DrawString(L"yes",-1,&font,PointF(200,10),&SolidBrush(Color::Red));  
  11. }else{  
  12.     graphics.FillRectangle(&SolidBrush(Color::White),RectF(200,10,100,100));  
  13. }  

转于:http://blog.csdn.net/harvic880925/article/details/9115125

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值