GDI+學習及代碼總結之------區域

轉自:http://blog.csdn.net/harvic880925/article/details/9115125


在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. }  


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章