轉自:http://blog.csdn.net/harvic880925/article/details/9115125
在GDI+中,對於區域的部分基本上使用了GDI的區域構造函數與合併方法,所以我們先看看GDI中的區域是如何構造與操作的。
GDI中區域構建與操作
一、基本函數
創建矩形區域:
- HRGN CreateRectRgnIndirect(CONST RECT *lprc);
- HRGN CreateRectRgn(
- int nLeftRect, // left點座標(X)
- int nTopRect, //top點座標值(Y)
- int nRightRect, //right點座標值(X)
- int nBottomRect //bottom點座標值(Y)
- );
- HRGN CreateEllipticRgnIndirect(
- CONST RECT *lprc // bounding rectangle
- );
- HRGN CreateEllipticRgn(
- int nLeftRect, // x-coord of upper-left corner of rectangle
- int nTopRect, // y-coord of upper-left corner of rectangle
- int nRightRect, // x-coord of lower-right corner of rectangle
- int nBottomRect // y-coord of lower-right corner of rectangle
- );
- HRGN CreatePolygonRgn(
- CONST POINT *lppt, // array of points
- int cPoints, // number of points in array
- int fnPolyFillMode // polygon-filling mode
- );
- int CombineRgn(
- HRGN hrgnDest, // handle to destination region
- HRGN hrgnSrc1, // handle to source region
- HRGN hrgnSrc2, // handle to source region
- int fnCombineMode // region combining mode
- );
RGN_COPY:原樣複製hrgnSrc1中的區域,一般不用這個,沒太大意義;
RGN_AND:合成的區域是hrgnSrc1和hrgnSrc2的重疊部分;
RGN_DIFF:合成的區域是hrgnSrc1中不包含hrgnSrc2的部分;
RGN_OR:合成的區域同時包含hrgnSrc2和hrgnSrc2;
RGN_XOR:合成的區域同時包含hrgnSrc2和hrgnSrc2,但不包含hrgnSrc2和hrgnSrc2的重疊部分;
區域的句柄可用的4個繪圖函數:
- FillRgn(hdc, hRgn, hBrush);// 類似FillRect
- FrameRgn(hdc, hRgn, hBrush, xFrame, yFrame);// 類似FrameRect
- InverRgn(hdc, hRgn); //類似InvertRect
- PaintRgn(hdc, hRgn);// 用設備描述表中的當前畫刷填充所指的區域。
刪除一個區域
- DeleteObject(hRgn);
- //Windows的2個作用於區域而不是矩形的函數
- InvalidateRgn(hwnd, hRgn, bErase); //類似於InvalidateRect
- ValidateRgn(hwnd, hRgn); //類似於ValidateRect
剪裁區域
首先是創建剪裁區域
- SelectObject(hdc, hRgn);
- SelectClipRgn(hdc, hRgn);
對剪裁區域的操作函數:
- ExcludeClipRect 用於將一個矩形從剪裁區域裏排除掉
- IntersectClipRect 用於創建一個新的剪裁區域,他是前一個剪裁區域與一個矩形的交集
- OffsetClipRgn 用於將剪裁區域移動到客戶區的另一部分
GDI會爲剪裁區域創建一個副本,所以在將新創建的區域選進設備描述表後,用戶可以刪除這個區域。
CombineRgn(hDestRgn, hSrcRgn1, hSrcRgn2, iCombine); 中使用的3個區域句柄必須都是有效的,即都要是創建了的。
在調用CombineRgn函數後,源區域即可以刪除了,刪除不會影響新合成的區域
看在GDI中使用區域函數的一個示例:(區域摳圖)
原理:先用圖片大小的矩形構造一個目的區域,所以這個區域的大小就是整個圖片的大小,然後從圖片的左上角(0,0)開始,按照從上到下、從左到右的順序形成長寬都爲1的矩形(就是一個像素大小),如果矩形中的背景是白色,將之從目的區域中去除,所以最終剩下的區域就是主畫面的區域了。這就是“摳”出主界面區域的關鍵思路所在。
先看下原來的圖片:
摳圖代碼:
- Bitmap photo(L"wlh.bmp");
- //得到相框尺寸
- INT iWidth=photo.GetWidth();
- INT iHeight=photo.GetHeight();
- graphics.DrawImage(&photo,0,0,iWidth,iHeight);
- //將繪圖平面右移,設置新的繪圖原點
- graphics.TranslateTransform(iWidth+10,0);
- Color color,colorTemp;
- HRGN endRgn=CreateRectRgn(0,0,iWidth,iHeight);
- //依次獲取相框的每一個相素
- for(int iRow=0;iRow<iHeight;iRow++){
- for(int iColumn=0;iColumn<iWidth;iColumn++){
- photo.GetPixel(iColumn,iRow,&color);
- //如果像素爲白色,從原有區域中去除當前區域點
- if(color.GetR()==255&&color.GetG()==255&&color.GetB()==255){
- HRGN tempRgn=CreateRectRgn(iColumn,iRow,iColumn+1,iRow+1);
- CombineRgn(endRgn,tempRgn,endRgn,RGN_XOR);
- }//if--end
- }
- }
- //創建GDI+區域變量
- Region fillrgn(endRgn);
- graphics.FillRegion(&SolidBrush(Color::Green),&fillrgn);
GDI+中的區域構建與操作
一、構造函數(Region):
- Region()
- Region(path) //從路徑構建
- Region(hRgn) //從GDI中的HRGN句柄構建
- Region(Rect& rect) //從矩形構建
- Region(RectF& rect)
- Region(regionData, size) //使用區域數組信息創建
- Region(hRgn) //從GDI中的HRGN句柄構建
- Region(Rect& rect) //從矩形構建
對於Region(Rect):Region類只提供了這麼一個矩形構造函數,沒有GDI中的橢圓、多邊形區域的構建方法,所以當我們構建橢圓、多邊形區域時,就是使用GDI了。
二、區域操作(構建區域)
對於GDI中的操作,我們知道CombineRgn的最後一個參數,可以實現對區域的RGN_AND、RGN_DIFF、RGN_OR、RGN_XOR
在GDI+中,Regin類中,也有對區域的操作函數,同樣實現了GDI中的區域操作功能,它們分別是:
- Region::Intersect(region)//求區域A和區域B的共有部分(交集)
- Region::Union(region)//求同時包含區域A和區域B的區域(並集)
- Region::Xor(region)//求不包含區域A和區域B相交部分的區域(異並集,又稱爲對稱差)
- Region::Complement(region)//求區域B中不含區域A的區域(A的補集)
- Region::Exclude(region)//求區域A中不含區域B的區域(B的補集)
- //異並集(集合的對稱差):設A、B爲任意兩個集合,A和B的對稱差爲集合S,其元素或屬於A,或屬於B,但不能即屬於A又屬於B,這樣的集合S稱爲集合A與B的對稱差
簡單的看一個示例吧,(異並集的)
- Region rgn1(RectF(25,10,50,100));
- Region rgn2(RectF(0,50,100,30));
- Pen pen1(Color::Red,2);
- Pen pen2(Color::Blue,2);
- SolidBrush brush(Color::Green);
- rgn1.Xor(&rgn2);
- graphics.TranslateTransform(20,0);//轉變繪製原點,這裏這句並不是必須的,我只是爲了讓大家記住這個函數
- graphics.FillRegion(&brush,&rgn1);
- graphics.DrawRectangle(&pen1,RectF(25,10,50,100));
- graphics.DrawRectangle(&pen2,RectF(0,50,100,30));
三、用矩形表示區域
對於特定的區域,我們都可以使用多個矩形來表示其大致形狀。事實上,如果矩形足夠小,一定數量的矩形就能夠精確表示區域的形狀,也就是說,一定數量的矩形所合成的形狀,也可以代表區域的形狀。Region類的GetRegionScans函數,實現了獲取組成區域的矩形集的功能,其調用格式如下:
- GetRegionScans(Matrix* matrix, Rect* rects, INT* count)
- GetRegionScans(Matrix* matrix, RectF* rects, INT* count)
matrix:[in]繪製平面上的座標變換矩陣
rects:[out]代表矩形集的數組
count:[out]矩形集的數量,該值可以通過GetRegionScansCount函數獲取。
示例:
- SolidBrush solidBrush(Color::Red);
- Pen pen(Color::Green);
- GraphicsPath path;
- Matrix matrix;
- Rect *rects=NULL;
- INT count=0;
- path.AddEllipse(10,0,80,120);
- Region patchRegion(&path);
- graphics.FillRegion(&solidBrush,&patchRegion);
- graphics.GetTransform(&matrix);
- count=patchRegion.GetRegionScansCount(&matrix);
- //爲矩形集分配空間
- rects=(Rect*)malloc(count*sizeof(Rect));
- patchRegion.GetRegionScans(&matrix,rects,&count);
- graphics.TranslateTransform(140,0);
- for(INT j=0;j<count;j++){
- graphics.DrawRectangle(&pen,rects[j]);
- }
- free(rects);
四、擊中測試區域(判斷點是否在區域內)
擊中測試(HitTest),簡單地說就是判斷一個點是否位於指定的區域內。Region類的成員函數IsVisible提供了這樣一個功能。而且還提供了擴展:不僅可以測試一個點是否位於指定的區域中,還可以測試兩矩形區域是存否在交集。IsVisible的調用格式爲:
- IsVisible(Point& point, Graphics* g)
- IsVisible(PointF& point, Graphics* g)
- IsVisible(Rect& rect, Graphics* g)
- IsVisible(RectF& rect, Graphics* g)
- IsVisible(INT x, INT y, Graphics* g)
- IsVisible(REAL x, REAL y, Graphics* g)
- IsVisible(INT x, INT y, INT width, INT height, Graphics* g)
- 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)添加如下代碼:
- Graphics graphics(this->GetDC()->m_hDC);
- FontFamily ff(L"Arial");
- Font font(&ff,15,FontStyleRegular,UnitPixel);
- Region rgn(RectF(10,10,100,200));
- bool binrgn=rgn.IsVisible(point.x,point.y,&graphics);
- graphics.DrawRectangle(&Pen(Color::Green,2),RectF(10,10,100,200));
- if(binrgn){
- graphics.DrawString(L"yes",-1,&font,PointF(200,10),&SolidBrush(Color::Red));
- }else{
- graphics.FillRectangle(&SolidBrush(Color::White),RectF(200,10,100,100));
- }