程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC.net >> Visual C++.NET GDI+編程基礎

Visual C++.NET GDI+編程基礎

編輯:VC.net
GDI+提供從簡單到復雜圖形繪制的大量方法,並且我們可以通過對路徑和區域的操作構造出更復雜的圖形,這在CAD等場合極為有用。當然,在繪圖之前我們有必要搞清一些基本內容,如坐標空間、畫筆和畫刷等。

  坐標空間及其變換

  在視圖和窗口中繪圖或定位總是在一個二維坐標系進行,依據作用方法的不同,坐標有多種表示方法,並且各種不同坐標之間可以相互轉換。

  1. 世界坐標系、設備坐標系和頁面坐標系

  GDI+為我們提供了三種坐標空間:世界坐標系、頁面坐標系和設備坐標系。

  "世界坐標系"是應用程序用來進行圖形輸入輸出所使用的一種與設備無關的笛卡爾坐標系。通常,我們可以根據自己的需要和方便定義一個自己的世界坐標系,這個坐標系稱為用戶坐標系。例如,前面"DrawLine(&newPen, 20, 10, 200, 100);"中的坐標都是以這個用戶坐標系為基准的,默認時使用像素為單位。

  "設備坐標系"是指顯示設備或打印設備坐標系下的坐標,它的特點是以設備上的象素點為單位。對於窗口中的視圖而言,設備坐標的原點在客戶區的左上角,x坐標從左向右遞增,y坐標自上而下遞增。由於設備的分辨率不同,相同坐標值的物理位置可能不同。如對於邊長為100的正方形,當顯示器為640 x 480和800 x 600時的大小是不一樣的。

  "頁面坐標系"是指某種映射模式下的一種坐標系。所謂映射是指將世界坐標系通過某種方式進行的變換。默認時,設備坐標和頁面坐標是一致的。

  2. 坐標映射和坐標原點的設置

  為了能保證打印或顯示的結果不受設備的影響,GDI+定義了一些映射方法和屬性來決定設備坐標和頁面坐標之間的關系。這些映射方法和屬性有:

   SetPageUnit和GetPageUnit

  這兩個屬性函數是用來設置和獲取每個單位所對應的實際度量單位。它通常可以有下列的值:

UnitDisplay -- 每個頁面單位為1/75英寸;
UnitPixel -- 每個頁面單位為1個像素,此時頁面坐標與設備坐標相同;
UnitPoint -- 每個頁面單位為1/72英寸;
UnitInch -- 每個頁面單位為1英寸;
UnitDocument -- 每個頁面單位為1/300英寸;
UnitMillimeter-- 每個頁面單位為1毫米。

  例如,或將Ex_GDIPlusDlg示例中的繪圖代碼修改成:

程序代碼:
CPaintDC dc(this); 
using namespace Gdiplus;
Graphics graphics( dc.m_hDC );
graphics.SetPageUnit(UnitMillimeter);
Pen newPen( Color( 255, 0, 0 ), 3 );
HatchBrush newBrush( HatchStyleCross,
Color(255, 0, 255, 0),
Color(255, 0, 0, 255)); 
graphics.DrawRectangle( &newPen, 50, 50, 100, 60); 
graphics.FillRectangle( &newBrush, 50, 50, 100, 60);
  則筆畫寬度為3,以及矩形的左上角頂點坐標和大小單位都為毫米,其結果如圖所示。



  SetPageScale和GetPageScale

 GDI+的這兩個屬性函數分別用來設置和獲取頁面的縮放比例。例如,當上面的繪圖代碼變成:

程序代碼:
...
graphics.SetPageUnit(UnitMillimeter);
graphics.SetPageScale( (REAL)0.1);
Pen newPen( Color( 255, 0, 0 ), 3 );
...


  代碼中,REAL是一個浮點類型的定義。上述代碼的結果如圖2所示。


圖2

  TranslateTransform

  GDI+的TranslateTransform方法用來改變坐標的原點位置,例如TranslateTransform(100, 50)是將坐標原點移到點(100,50)。

  畫筆

  畫筆是用來繪制各種直線和曲線的一種圖形工具,GDI+的Pen類為畫筆提供了豐富的方法。一般來說,我們可以通過其構造函數來指定畫筆的顏色和寬度,其定義如下:

程序代碼:
Pen( const Color& color, REAL width );


  其中,color是用來指定畫筆顏色,width用來指定畫筆寬度。REAL是一個float類型定義,而Color是GDI+的一個顏色類,它既可以指定一個ARGB顏色類型,也可以使用GDI+預定義的顏色值,甚至可以將COLORREF轉換成Color類型的顏色。例如,下面的代碼都是創建一個寬度為3,顏色為藍色的畫筆:

程序代碼:

Pen newPen( Color( 255, 0, 0, 255 ), 3 );

Pen newPen(Color( 0, 0, 255), 3);
// 當Color只有三個實參時,顏色Alpha分量值為255。

Pen newPen(Color::Blue, 3);

COLORREF crRef = RGB( 0, 0, 255);
Color color;
color.SetFromCOLORREF(crRef);
Pen newPen(color, 3);

  除了顏色外,GDI+的Pen類還提供SetDashStyle和SetDashPattern方法來設置畫筆的預定義風格和自定義類型。其中,預定義風格可以有:DashStyleSolid(實線)、DashStyleDash(虛線)、DashStyleDot(點線)、DashStyleDashDot(點劃線)、DashStyleDashDotDot(雙點劃線)和DashStyleCustom(自定義類型)。例如下列代碼,其結果如圖7.6所示:

程序代碼:

using namespace Gdiplus;
Graphics graphics( pDC->m_hDC );
Pen pen(Color(255, 0, 0, 255), 15);

pen.SetDashStyle(DashStyleDash);
graphics.DrawLine(&pen, 0, 50, 400, 150);

pen.SetDashStyle(DashStyleDot);
graphics.DrawLine(&pen, 0, 80, 400, 180); 

pen.SetDashStyle(DashStyleDashDot);
graphics.DrawLine(&pen, 0, 110, 400, 210); 



  但是,在工程應用中,預定義風格的畫筆有時並不能滿足實際的需求,而必須自己定義一些線型,這需要通過SetDashPattern函數來實現。SetDashPattern的原型如下:

程序代碼:

Status SetDashPattern( const REAL* dashArray, INT count);


  其中,dashArray是一個包含短劃和間隔長度的數組,count表示數組的大小。注意,dashArray中的短劃長度和間隔長度是成對出現的,例如下列代碼是使用自定義類型的畫筆,其結果如圖7.7所示。

程序代碼:

REAL dashVals[4] = {
2, // 短劃長為2
2, // 間隔為2
15, // 短劃長為15
2}; // 間隔為2
Pen pen(Color(255, 0, 0, 0), 5);
pen.SetDashPattern(dashVals, 4);
graphics.DrawLine(&pen, 5, 20, 405, 200); 



  需要說明的是,GDI+的Pen類還提供SetStartCap和SetEndCap方法來設置一條直線的起始端和終止端的樣式。例如下面的代碼,其結果如圖7.8所示。

程序代碼:

using namespace Gdiplus;
Graphics graphics( pDC->m_hDC );

Pen pen( Color( 255, 0, 0, 255 ), 15); 

pen.SetStartCap(LineCapFlat);
pen.SetEndCap(LineCapSquare);
graphics.DrawLine(&pen, 50, 50, 250, 50);

pen.SetStartCap(LineCapRound );
pen.SetEndCap(LineCapRoundAnchor);
graphics.DrawLine(&pen, 50, 100, 250, 100); 

pen.SetStartCap(LineCapDiamondAnchor);
pen.SetEndCap(LineCapArrowAnchor);
graphics.DrawLine(&pen, 50, 150, 250, 150); 

  畫刷和漸變

  畫刷用於指定填充的特性,GDI+為填充色和陰影線畫刷提供了SolidBrush和HatchBrush類。通過它們的構造函數直接可以創建一個畫刷,其構造函數的原型如下:

程序代碼:

SolidBrush( const Color& color);

HatchBrush( HatchStyle hatchStyle, const Color& foreColor,
const Color& backColor);

  其中,foreColor和backColor用來指定陰影線顏色和填充的背景顏色,背景色可以不指定。hatchStyle用來指定陰影線的樣式,它可以是這樣的一些預定義樣式:HatchStyleHorizontal (水平線)、HatchStyleVertical(垂直線)、HatchStyleForwardDiagonal(上斜線)、HatchStyleBackwardDiagonal(下斜線)、HatchStyleCross(十字線)以及HatchStyleDiagonalCross (交叉線)等。當然,還有許多樣式如HatchStyle30Percent(30%填充)、HatchStyleSolidDiamond (實心菱形)等,這裡不一一列舉。

  由於在前面的示例中,對這種簡單的畫刷的使用已介紹過,因而這裡著重討論漸變畫刷的創建和使用。
GDI+提供了LinearGradientBrush和PathGradientBrush類分別用來創建一個直線漸變和路徑漸變畫刷。

  直線漸變是指在一個矩形區域使用兩種顏色進行過渡(漸變),過渡方向可以是水平、垂直以及對角線方向。LinearGradientBrush構造函數的原型如下:

程序代碼:
LinearGradientBrush(Point & point1, Point & point2, 
Color & color1, Color & color2);
LinearGradientBrush(Rect & rect, Color & color1, Color & color2, 
REAL angle, BOOL isAngleScalable);
LinearGradientBrush(Rect & rect, Color & color1, Color & color2, 
LinearGradientMode mode);

  其中,point1和point2分別用來指定矩形區域的左上角和右下角點坐標,color1和color2分別用來指定漸變起始和終止的顏色。rect用來指定一個矩形區域的大小和位置,angle用來指定漸變的方向角度,正值為順時針。isAngleScalable是一個即將廢除的參數。mode用來指定漸變的方法,它可以是LinearGradientModeHorizontal(水平方向)、LinearGradientModeVertical (垂直方向)、LinearGradientModeForwardDiagonal(從左下到右上的對角線方向)和LinearGradientModeBackwardDiagonal(從左上到右下的對角線方向)。

  需要說明的是,Point和Rect是GDI+新的數據類型,它們和MFC的CPoint和CRect類的功能基本一樣,但它們相互之間不能混用。

  路徑漸變畫刷是用漸變顏色來填充一個封閉的路徑。一個路徑既可以由一系列的直線和曲線構成,也可以由其它對象來構造。路徑漸變是一種中心顏色漸變模式,它從路徑的中心點向四周進行顏色漸變。PathGradientBrush構造函數的原型如下:

程序代碼:
PathGradientBrush(const GraphicsPath* path); 
PathGradientBrush(const Point * points, INT count, WrapMode wrapMode);

  其中,path用來指定一個路徑指針,points和count分別用來指定組成路徑的一系列直線端點的數組及其大小,wrapMode是一個可選項,用來指定填充的包圍模式。一個包圍模式用來決定是否在區域內部、在區域外部以及所有區域都填充。默認時,其值為WrapModeClamp,即在區域內部填充。

  下面的代碼說明了上述兩種漸變畫刷的使用方法:

程序代碼:
Graphics graphics( pDC->m_hDC );

GraphicsPath path; // 構造一個路徑
path.AddEllipse(50, 50, 200, 100);

// 使用路徑構造一個畫刷
PathGradientBrush pthGrBrush(&path);

// 將路徑中心顏色設為藍色
pthGrBrush.SetCenterColor(Color(255, 0, 0, 255));

// 設置路徑周圍的顏色為藍芭,但alpha值為0
Color colors[] = {Color(0, 0, 0, 255)};
INT count = 1;
pthGrBrush.SetSurroundColors(colors, &count);

graphics.FillRectangle(&pthGrBrush, 50, 50, 200, 100);

LinearGradientBrush linGrBrush(
Point(300, 50),
Point(500, 150),
Color(255, 255, 0, 0), // 紅色
Color(255, 0, 0, 255)); // 藍色

graphics.FillRectangle(&linGrBrush, 300, 50, 200, 100);

  結果如圖7.9所示。

  需要說明的是,畫筆和畫刷還可使用一個圖片來創建。例如下列代碼,其結果如圖7.10所示。

程序代碼:

Graphics graphics( pDC->m_hDC );

Image image(L"image.jpg");
TextureBrush tBrush(&image);
Pen texturedPen(&tBrush, 10);

graphics.DrawLine(&texturedPen, 25, 25, 325, 25);
tBrush.SetWrapMode(WrapModeTileFlipXY);
graphics.FillRectangle(&tBrush, 25, 100, 300, 200);


  圖形幾何變換

  圖形變換一般是對圖形的幾何信息經過幾何變換後產生新的圖形。常見二維圖形的變換有平移、比例、對稱、旋轉、錯切等。圖形幾何變換最有效的手段是采用矩陣變換,GDI+就有這樣的矩陣類Matrix,它為我們提供了許多變換的方法,如Invert(轉置)、Multiply(矩陣相乘)、Rotate(旋轉)等。例如下面的代碼就是Matrix::Rotate一個例子,其結果如圖7.11所示。

程序代碼:

Graphics graphics( pDC->m_hDC );
Pen pen(Color(255, 0, 0, 255));

Matrix matrix;
matrix.Translate(40, 0); // 先平移
matrix.Rotate(30, MatrixOrderAppend); // 後旋轉

graphics.SetTransform(&matrix);
graphics.DrawEllipse(&pen, 0, 0, 100, 50);


  需要說明的是,代碼中的MatrixOrderAppend用來指明第二個矩陣(若有)的操作次序是後置的,即matrix1 OP matrix2,OP表示某種操作;若為MatrixOrderPrepend 則表示matrix2 OP matrix1。而SetTransform則指定一個矩陣對點坐標進行變換,新的坐標點(x*,y*)結果可用下列公式來表示:

[x* y* 1] = [x y 1] = [m11x+m21y+dx m12x+m22y+dy 1]

式中,dx和dy用來指定x和y方向的平移量,若dx = dy = 0,則:

  (1) 當m21 = m12 = 0,m11 = -1,m22 = 1時,有x*= -x,y*= y,產生與y軸對稱的反射圖形;

  (2) 當m21 = m12 = 0,m11 = 1,m22 = -1時,有x*= x,y*= -y,產生與x軸對稱的反射圖形;

  (3) 當m21 = m12 = 0,m11 = m22 = -1時,有x*= -x,y*= -y,產生與原點對稱的反射圖形;

  (4) 當m21 = m12 = 1,m11 = m22 = 0時,有x*= y,y*= x,產生與直線y = x對稱的反射圖形;

  (5) 當m21 = m12 = -1,m11 = m22 = 0時,有x*= -y,y*= -x,產生與直線y = -x對稱的反射圖形;

  (6) 而當m11 = m22 = cosq,m21 = -m12 = sinq 時,則進行旋轉變換。

  例如下列代碼,其結果如圖7.12所示。

程序代碼:

Graphics graphics( pDC->m_hDC );
Pen pen(Color::Blue,3);
graphics.DrawLine(&pen, 150,50,200,80);

pen.SetColor(Color::Gray);
Matrix matrix( -1,0,0,1, 150,50); // 使用第一種情況

graphics.SetTransform(&matrix);
graphics.DrawLine(&pen, 0,0,50,30);



  其中,Matrix的構造函數有如下定義:

程序代碼:

Matrix( REAL m11, REAL m12, REAL m21, REAL m22, REAL dx, REAL dy);

  需要說明的是,除了使用Matrix進行圖形變換外,Graphics本身提供相應的變換方法,如RotateTransform(旋轉變換)、ScaleTransform(比例變換)和TranslateTransform(平移變換)等。

  基本繪圖函數

  在前面許多示例中,我們已經用到如DrawLine等基本繪圖函數。除此之外,還有許多這樣的函數,並且每個繪圖函數都有其重載形式,這給我們帶來了許多方便。表7.1列出這些基本繪圖函數。

  表1 GDI+常用基本繪圖函數

繪圖函數 功能描述 DrawArc 繪制一條圓弧曲線,范圍由起止角大小決定,大小由矩形或長寬值指定 DrawBezier 繪制一條由一系列型值頂點決定的三次Bezier曲線 DrawBeziers 繪制一系列的三次Bezier曲線 DrawClosedCurve 繪制一條封閉的樣條曲線 DrawCurve 繪制一條樣條曲線 DrawEllipse 繪制一條橢圓輪廓線,大小由矩形或長寬值指定 DrawLine 繪制一條直線 DrawPath 繪制由GraphicsPath定義的路徑輪廓線 DrawPie 繪制一條扇形(餅形)輪廓線 DrawPolygon 繪制一個多邊形的輪廓線 DrawRectangle 繪制一個矩形 FillEllipse 填充一個橢圓區域 FillPath 填充一個由路徑指定的區域 FillPie 填充一個扇形(餅形)區域 FillPolygon 填充一個多邊形區域 FillRectangle 填充一個矩形區域 FillRectangles 用同一個畫刷填充一系列矩形區域 FillRegion 填充一個區域(Region)的內部
  下面的代碼是通過路徑用兩條樣條曲線構造一個復雜的區域,然後填充它,其結果如圖7.13所示。

程序代碼:
Graphics graphics( pDC->m_hDC );

Pen pen(Color::Blue, 3);
Point point1( 50, 200);
Point point2(100, 150);
Point point3(160, 180);
Point point4(200, 200);
Point point5(230, 150);
Point point6(220, 50);
Point point7(190, 70);
Point point8(130, 220);

Point curvePoints[8] = {point1, point2, point3, point4,
point5, point6, point7, point8};
Point* pcurvePoints = curvePoints;

GraphicsPath path;
path.AddClosedCurve(curvePoints, 8, 0.5);

PathGradientBrush pthGrBrush(&path);
pthGrBrush.SetCenterColor(Color(255, 0, 0, 255));
Color colors[] = {Color(0, 0, 0, 255)};
INT count = 1;
pthGrBrush.SetSurroundColors(colors, &count);

graphics.DrawClosedCurve(&pen, curvePoints, 8, 0.5);
graphics.FillPath(&pthGrBrush, &path);

    No
  1. 下一頁:
Copyright © 程式師世界 All Rights Reserved