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

来源:互联网 发布:mac 开启acl 编辑:程序博客网 时间:2024/06/06 20:12

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

GDI中区域构建与操作

一、基本函数

创建矩形区域:

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

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

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

先看下原来的图片:

先看下原来的图片:

抠图代码:

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

[cpp] view plaincopy
  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 plaincopy
  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 plaincopy
  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 plaincopy
  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 plaincopy
  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 plaincopy
  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 plaincopy
  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
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 替嫁医妃有空间 重生之农门贵夫 野性偏爱 嫁给病弱太子后我躺赢了 咸鱼娘娘一心只想翻墙 救命!破产后高冷总裁处处招惹我 冷酷将军每天都想要贴贴 何以赎光 甜腻!病娇傅少竟然暗恋我! 天价萌妻:偏执帝少心尖宠 有读心术后,战神把娘子宠上天 穿书后,我刷错了反派的好感度 摄政王怀里的团宠美人娇又软 满级千金不想掉马 女帝她就是个卖药的! 华娱激荡年代 她来看我的演唱会 快穿:娇养反派大佬做替身 不努力种田就要和相公继承皇位了 穿书末世之我是金手指 转生恶少后的魔幻日常 穿书后我成了反派男二的铁血妈粉 带着超市重返年代 新婚夜,我被冷冰冰的王爷读心了 修仙女配拿了反派剧本 影后的假面童话 克死前夫后我成了心软的神 新婚夜,我治好了失明太子的隐疾 沦陷野玫瑰 完球!我的崽居然是反派 重生后她被憨憨相公娇宠了 师祖回归,徒弟各个是疯批大佬 植物人老公苏醒后,她只想逃 他怎么可能是魔尊 农家小团宠:带着空间撩大佬 快穿做个好婆婆 医路芳华 满级真千金:一品女法医 惊!举重妖精被电竞奶狗缠上了 团宠小农女:带着功德空间去逃荒 被迫快穿后我只想当咸鱼