原文:http://cs.cqut.edu.cn/NetTeachPlatform/Chapter8.htm
第8章 繪制圖像
本章要求掌握用GDI+繪制直線、圓、長方形等圖形,在第七章的基礎上編寫一個類似於“畫圖”圖像圖形處理程序
8.1 繪圖所用到的常用控件及類
繪圖用到的PictureBox,Image, Bitmap, OpenFileDialog,SaveFileDialog等控件或類在前一章已經進行了講解。現對所用的其它控件或類進行說明。
8.1.1 顏色
在繪制圖形時需要指定使用的顏色,在GDI+中,顏色用System.Drawing.Color 結構來表示的。
1 紅綠藍(RGB)值
監視器可以顯示的顏色總數非常大—— 超過160萬。其確切的數字是2的24次方,即16 777 216。顯然,我們需要對這些顏色進行索引,才能指定在給定的某個像素上要顯示什么顏色。
給顏色進行索引的最常見方式是把它們分為紅綠藍成分,每種成份的光分為256種不同的強度,其值在0~255之間。
2 設置顏色的方法
l 可以調用靜態函數Color.FromArgb()指定該顏色的紅綠藍值。
其格式為
public static Color FromArgb (
int red,
int green,
int blue
)
例如:
Color red = Color.FromArgb(255, 0, 0);
Color green = Color.FromArgb(0, 255, 0);
Color blue = Color.FromArgb(0, 0, 255);
l 獲取系統定義的顏色
使用FromArgb()構造顏色是一種非常靈活的技巧,因為它表示我們可以指定人眼能辨識出的任何顏色。但是,如果要得到一種簡單、標准、眾所周知的純色,例如紅色或藍色,命名想要的顏色是比較簡單的。因此Microsoft還在Color中提供了許多靜態屬性,每個屬性都返回一種命名的顏色。在下面的示例中,把窗口的背景色設置為白色時,就使用了其中一種屬性:
this.BackColor = Color.White;
// 與以下語句效果一樣
// this.BackColor = Color.FromArgb(255, 255 , 255);
8.1.2 畫筆和鋼筆
本節介紹Pen和Brush,在繪制圖形時需要使用它們。Pen用於告訴graphics實例如何繪制線條。Brush如何填充區域。例如,Pen用於繪制矩形和橢圓的邊框。如果需要把這些圖形繪制為實心的,就要使用畫筆指定如何填充它們。
1畫筆
GDI+有幾種不同類型的畫筆。每種畫筆都由一個派生自抽象類System.Drawing.Brush的類實例來表示。最簡單的畫筆為System.Drawing.SolidBrush。它是單色畫筆,用於填充圖形形狀,如矩形、橢圓、扇形、多邊形和封閉路徑。
Color customColor = Color.FromArgb(192,192,192);
SolidBrush shadowBrush = new SolidBrush(customColor);
或者
SolidBrush shadowBrush = new SolidBrush(Color.Gray);
2與畫筆不同,鋼筆只用一個類System.Drawing.Pen來表示。但鋼筆比畫筆復雜一些,因為它需要指定線條應有多寬(像素),對於一條比較寬的線段,還要確定如何填充該線條中的區域。
Pen solidBluePen = new Pen(Color.FromArgb(0,0,255));
Pen solidWideBluePen = new Pen(Color.Blue, 4);
8.2 繪圖所用到的結構
GDI+使用幾個類似的結構來表示坐標或區域。下面介紹幾個結構,它們都是在System.Drawing命名空間中定義的,如表8.1所示。
表 8-1 Point、Size及Rectangle結構
|
|
結 構 |
主要的公共屬性 |
| Point |
X,Y |
|
| PointF |
||
|
|
Size |
Width, Height |
|
|
SizeF |
|
| Rectangle |
Left, Right , Top, Bottom, Width, Height, X, Y, Location, Size |
|
| RectangleF |
||
8.2.1 Point和PointF結構
表示圖像的一點,從概念上講,Point在這些結構中是最簡單的,在數學上,它完全等價於一個二維矢量。我們可以創建一個Point結構:
Point b = new Point(20, 10);
X和Y都是讀寫屬性,也可以在Point中設置這些值:
Point a = new Point();
a.X = 20;
b.Y = 10;
PointF與Point完全相同,但X和Y屬性的類型是float,而不是int。PointF用於坐標不是整數值的情況。注意,可以把Point隱式轉換為 PointF,但要把PointF轉換為Point,必須顯式地復制值,或使用下面的3個轉換方法Round()、Truncate()和Ceiling()。
Point b = new Point();
b.X = (int)abFloat.X;
b.Y = (int)abFloat.Y;
// Point隱式轉換為 PointF
PointF bFloat1 = ab;
// PointF顯式轉換為 Point
Point b1 = Point.Round(bFloat);
Point b2 = Point.Truncate(bFloat);
Point b3 = Point.Ceiling(bFloat);
8.2.2 Size和SizeF結構
與Point和PointF一樣,Size也有兩個屬性。Size結構用於int類型,SizeF用於float類型,除此之外,Size和 SizeF是完全相同的。下面主要討論Size結構。
在許多情況下,Size結構與Point結構是相同的,它也有兩個整型屬性,表示水平和垂直距離—— 主要區別是這兩個屬性的名稱不是X和Y,而是Width 和 Height。前面的圖30-3可以表示為:
Size ab = new Size(20,10);
嚴格地講,Size在數學上與Point表示的含義相同;但在概念上它使用的方式略有不同。Point用於說明實體在什么地方,而Size用於說明實體有多大。
8.2.3 Rectangle和RectangleF結構
這兩個結構表示一個矩形區域(通常在屏幕上)。與Point 和 Size一樣,這里只介紹Rectangle結構,RectangleF與Rectangle基本相同,但它的屬性類型是float,而Rectangle的屬性類型是int。
Rectangle可以看作由一個Point 和一個 Size組成,其中Point表示矩形的左上角,Size表示其大小。它的一個構造函數把Point 和 Size作為其參數
Point topLeft = new Point(0,0);
Size howBig = new Size(50,50);
Rectangle rectangleArea = new Rectangle(topLeft, howBig);
8.3繪制圖形和線條
System.Drawing.Graphics 有很多方法,利用這些方法可以繪制各種線條、空心圖形和實心圖形。表8.2所示的列表並不完整,但給出了主要的方法。本書只講解對直線、空實心矩形及橢圓進行繪制,其它圖形的繪制感興趣的同學可以查閱MSDN。
表 8.2 繪制圖形的基本方法
| 方 法 |
常 見 參 數 |
繪制的圖形 |
| DrawLine |
鋼筆、起點和終點 |
一段直線 |
| DrawRectangle |
鋼筆、位置和大小 |
空心矩形 |
| DrawEllipse |
鋼筆、位置和大小 |
空心橢圓 |
| FillRectangle |
畫筆、位置和大小 |
實心矩形 |
| FillEllipse |
畫筆、位置和大小 |
實心橢圓 |
| DrawLines |
鋼筆、點數組 |
一組線,把數組中的每個點按順序連接起來 |
| DrawBezier |
鋼筆、4個點 |
通過兩個端點的一條光滑曲線,剩余的兩個點用於控制曲線的形狀 |
| DrawCurve |
鋼筆、點數組 |
通過點的一條光滑曲線 |
| DrawArc |
鋼筆、矩形、兩個角 |
由角度定義的矩形中圓的一部分 |
| DrawClosedCurve |
鋼筆、點數組 |
與DrawCurve一樣,但還要繪制一條用以閉合曲線的直線 |
| DrawPie |
鋼筆、矩形、兩個角 |
矩形中的空心楔形 |
| FillPie |
畫筆、矩形、兩個角 |
矩形中的實心楔形 |
| DrawPolygon |
鋼筆、點數組 |
與DrawLines 一樣,但還要連接第一點和最后一點,以閉合繪制的圖形 |
8.3.1 畫直線
(1)繪制一條連接兩個 Point 結構的線,
public void DrawLine (
Pen pen,
Point start,
Point end
)
pen,它確定線條的顏色、寬度和樣式。
start,Point 結構,它表示要連接的第一個點。
end ,Point 結構,它表示要連接的第二個點。
下面代碼繪制如圖8.1所示的直線,其顏色分別為黑、紅、黃及指定的RGB值,寬度分別為3,5,7,9。
Graphics g = this.CreateGraphics();
//創建不同顏色及精細的畫筆
Pen blackPen = new Pen(Color.Black, 3);
Pen redPen = new Pen(Color.Red, 5);
Pen yellowPen = new Pen(Color.Yellow, 7);
Pen mypen = new Pen(Color.FromArgb(167, 234, 89), 9);
//繪制黑線
Point start1 = new Point(100, 100);
Point end1 = new Point(200, 200);
g.DrawLine(blackPen, start1, end1);
//繪制紅線
Point start2 = new Point(200, 100);
Point end2 = new Point(300, 200);
g.DrawLine(redPen, start2, end2);
//繪制黃線
Point start3 = new Point(300, 100);
Point end3 = new Point(400, 200);
g.DrawLine(yellowPen, start3, end3);
//繪制RGB為(167, 234, 89)的直線
Point start4 = new Point(400, 100);
Point end4 = new Point(500, 200);
g.DrawLine(mypen, start4, end4);
圖 8.1 直線
(2)虛線
Pen 的DashStyle屬性,可以繪制虛線。
格式為
myPen.DashStlyle= DashStyle.類型
下面的示例繪制如圖8.2所示的虛線,其虛線類型分別為:Dash, Dot, DashDot, DashDotDot。
Graphics g = this.CreateGraphics();
Pen blackPen = new Pen(Color.Black, 3);
Pen redPen = new Pen(Color.Red, 5);
Pen yellowPen = new Pen(Color.Yellow, 7);
Pen mypen = new Pen(Color.FromArgb(167, 234, 89), 9);
blackPen.DashStyle = DashStyle.Dash;
redPen.DashStyle = DashStyle.Dot;
yellowPen.DashStyle = DashStyle.DashDot;
mypen.DashStyle = DashStyle.DashDotDot;
// Create points that define line.
Point start1 = new Point(100, 100);
Point end1 = new Point(200, 200);
g.DrawLine(blackPen, start1, end1);
Point start2 = new Point(200, 100);
Point end2 = new Point(300, 200);
g.DrawLine(redPen, start2, end2);
Point start3 = new Point(300, 100);
Point end3 = new Point(400, 200);
g.DrawLine(yellowPen, start3, end3);
Point start4 = new Point(400, 100);
Point end4 = new Point(500, 200);
g.DrawLine(mypen, start4, end4);
圖 8.2 虛線
(3)直線端點
以使用 Pen 對象的屬性為直線設置更多特性。StartCap 屬性和 EndCap 屬性指定直線端點的外觀;端點可以是平的、方形的、圓形的、三角形的或自定義的形狀。LineJoin 屬性用於指定連接的線相互間是斜接的(聯接時形成銳角)、斜切的、圓形的還是截斷的。
下面的代碼繪制如圖8.3所示帶端點的直線
Graphics g = this.CreateGraphics();
Pen blackPen = new Pen(Color.Black, 3);
Pen redPen = new Pen(Color.Red, 5);
Pen yellowPen = new Pen(Color.Yellow, 7);
Pen mypen = new Pen(Color.FromArgb(167, 234, 89), 9);
blackPen.StartCap =LineCap.Flat;
blackPen.EndCap = LineCap.ArrowAnchor;
redPen.StartCap = LineCap.DiamondAnchor;
redPen.EndCap = LineCap.RoundAnchor;
yellowPen.EndCap = LineCap.SquareAnchor;
mypen.EndCap = LineCap.Triangle;
// Create points that define line.
Point start1 = new Point(100, 100);
Point end1 = new Point(200, 200);
g.DrawLine(blackPen, start1, end1);
Point start2 = new Point(200, 100);
Point end2 = new Point(300, 200);
g.DrawLine(redPen, start2, end2);
Point start3 = new Point(300, 100);
Point end3 = new Point(400, 200);
g.DrawLine(yellowPen, start3, end3);
Point start4 = new Point(400, 100);
Point end4 = new Point(500, 200);
g.DrawLine(mypen, start4, end4);
圖8.3 帶端點的直線
8.3.2 畫空心矩形
繪制由 Rectangle 結構指定的矩形
public void DrawRectangle (
Pen pen,
Rectangle rect
)
pen ,Pen,它確定矩形的顏色、寬度和樣式。
rect ,表示要繪制的矩形的 Rectangle 結構。
下面代碼分別繪制如圖8.4所示的矩形,
Graphics g = this.CreateGraphics();
Pen blackPen = new Pen(Color.Black, 3);
//blackPen.DashStyle = DashStyle.Dash;
// 建立矩形.
Rectangle rect = new Rectangle(100, 100, 200, 200);
// 繪制黑色矩形
g.DrawRectangle(blackPen, rect);
Pen redPen = new Pen(Color.Red, 5);
//設置矩形虛線的類型
redPen.DashStyle = DashStyle.Dash;
// 建立矩形.
Rectangle rectred = new Rectangle(320,100, 200,200);
// 繪制紅色矩形
g.DrawRectangle(redPen, rectred);
圖8.4 矩形
8.3.3 畫實心矩陣
填充 Rectangle 結構指定的矩形的內部
格式:
public void FillRectangle (
Brush brush,
Rectangle rect
)
brush ,確定填充特性的 Brush。
rect ,Rectangle 結構,它表示要填充的矩形。
· 下面代碼繪制如圖8.5所示的實心矩形
Graphics g = this.CreateGraphics();
//建立黑色畫筆
SolidBrush blackBrush = new SolidBrush(Color.Black);
// 構建矩形對象.
Rectangle rect = new Rectangle(100, 100, 200, 200);
// 畫黑實心矩形.
g.FillRectangle(blackBrush, rect);
//建立灰色畫筆
SolidBrush grayBrush = new SolidBrush(Color.Gray);
Rectangle rectgray= new Rectangle(320, 100, 200, 200);
g.FillRectangle(grayBrush,rectgray);
圖 8.5 實形矩形
8.3.4 畫空心橢圓
格式:
public void DrawEllipse (
Pen pen,
Rectangle rect
)
下面代碼繪制如圖8.6所示的空心橢圓
Graphics g = this.CreateGraphics();
Pen blackPen = new Pen(Color.Black, 3);
//構建矩形對象.
Rectangle rect = new Rectangle(100, 100, 200, 100);
// 畫空心空心橢圓.
g.DrawEllipse(blackPen, rect);
Rectangle rectgray = new Rectangle(320, 100, 200, 100);
//建立灰色畫筆
Pen grayPen = new Pen(Color.Gray, 5);
//指定虛線類型
grayPen.DashStyle = DashStyle.DashDotDot;
//繪制虛線橢圓
g.DrawEllipse(grayPen, rectgray);
圖 8.6 空心橢圓
8.3.5 繪制弧線
弧線是橢圓的一部分。若要繪制弧線,可調用 Graphics 類的 DrawArc 方法。除了 DrawArc 需要有起始角度和仰角以外,DrawEllipse 方法的參數與 DrawArc 方法的參數相同。
public void DrawArc (
Pen pen,
RectangleF rect,
float startAngle,
float sweepAngle
)
參數
pen 為Pen類型 ,它確定弧線的顏色、寬度和樣式。
rect 為RectangleF 結構,它定義橢圓的邊界。
startAngle 從 x 軸到弧線的起始點沿順時針方向度量的角(以度為單位)。
sweepAngle從 startAngle 參數到弧線的結束點沿順時針方向度量的角(以度為單位)。
下面代碼繪制如圖8.7所示的弧線
結果是部分橢圓,缺少 x 軸兩側 + 45 度和 - 45 度之間的部分。
Graphics g = this.CreateGraphics();
Pen blackPen = new Pen(Color.Black, 3);
// 建立矩形
RectangleF rect = new RectangleF(100.0F, 100.0F, 200.0F, 100.0F);
// 指定起始角,終止角
float startAngle =45.0F;
float sweepAngle = 270.0F;
// 畫黑色弧線.
g.DrawArc(blackPen, rect, startAngle, sweepAngle);
//建立灰色畫筆
Pen grayPen = new Pen(Color.Gray, 7);
//指定弧線的端點類型
grayPen.StartCap=LineCap.DiamondAnchor;
grayPen.EndCap = LineCap.ArrowAnchor;
//指定虛線的類型
grayPen.DashStyle = DashStyle.Dash;
// // 建立第二橢圓的邊界矩形
RectangleF rectgray = new RectangleF(320.0F, 100.0F, 200.0F, 100.0F);
//指定起始角,終止角
startAngle = -90.0F;
sweepAngle = 135.0F;
// 畫灰色弧線.
g.DrawArc(grayPen, rectgray, startAngle, sweepAngle);
圖 8.7 弧線
8.3.6 畫實心橢圓
格式:
public void FillEllipse (
Brush brush,
Rectangle rect
)
brush ,確定填充特性的 Brush。
rect ,Rectangle 結構,它表示定義橢圓的邊框。
· 代碼繪制如圖8.8所示的實心橢圓
Graphics g = this.CreateGraphics();
SolidBrush blackBrush = new SolidBrush(Color.Black);
// Create rectangle for ellipse.
int x = 100;
int y = 100;
int width = 200;
int height = 100;
Rectangle rect = new Rectangle(x, y, width, height);
// Fill ellipse on screen.
g.FillEllipse(blackBrush, rect);
SolidBrush grayBrush = new SolidBrush(Color.Gray);
// Create rectangle for ellipse.
x = 320;
y = 100;
width = 200;
height = 100;
Rectangle rectgray = new Rectangle(x, y, width, height);
// Fill ellipse on screen.
g.FillEllipse(grayBrush, rectgray);
本節介紹如果繪制的內容不適合窗口的大小,需要做哪些工作。
圖8.8 實心橢圓
8.3.7 繪制多邊形
多邊形是有三條或更多直邊的閉合圖形。例如,三角形是有三條邊的多邊形,矩形是有四條邊的多邊形,五邊形是有五條邊的多邊形。圖8.9的插圖顯示了幾個多邊形。
圖8.9多邊形
格式:
public void DrawPolygon (
Pen pen,
Point[] points
)
其中,points 為Point 結構數組,這些結構表示多邊形的頂點。
下面的代碼用於繪制如圖8.10所示的多邊形:
Graphics g = this.CreateGraphics();
Pen blackPen = new Pen(Color.Black, 3);
// 建立多邊形的各頂點
Point point1 = new Point(50, 150);
Point point2 = new Point(100, 125);
Point point3 = new Point(200, 115);
Point point4 = new Point(250, 150);
Point point5 = new Point(300, 200);
Point point6 = new Point(350, 300);
Point point7 = new Point(250, 350);
Point[] curvePoints =
{
point1,
point2,
point3,
point4,
point5,
point6,
point7
};
// 繪制多邊形
g.DrawPolygon(blackPen, curvePoints);
圖8.10 繪制多邊形
繪制實多邊形
格式:
public void FillPolygon (
Brush brush,
Point[] points
)
brush 為確定填充特性的 Brush。
Points為Point 結構數組,這些結構表示要填充的多邊形的頂點。
下面代碼繪制如圖8.11所示的實多邊形
Graphics g = this.CreateGraphics();
SolidBrush blackBrush = new SolidBrush(Color.Black);
// Create points that define polygon.
Point point1 = new Point(50, 150);
Point point2 = new Point(100, 125);
Point point3 = new Point(200, 115);
Point point4 = new Point(250, 150);
Point point5 = new Point(300, 200);
Point point6 = new Point(350, 300);
Point point7 = new Point(250, 350);
Point[] curvePoints =
{
point1,
point2,
point3,
point4,
point5,
point6,
point7
};
// Draw polygon to screen.
g.FillPolygon(blackBrush, curvePoints);
圖8.11實心多邊形
8.4 GDI+ 中的畫筆和實心形狀
閉合的形狀(例如,矩形或橢圓)由輪廓和內部組成。用鋼筆繪制出輪廓,並用畫筆填充其內部。GDI+ 提供了幾種填充閉合形狀內部的畫筆類:SolidBrush、HatchBrush、TextureBrush、LinearGradientBrush 和 PathGradientBrush。所有這些類都是從 Brush 類繼承的。下面的插圖顯示了用實心畫筆填充的矩形和用陰影畫筆填充的橢圓。
圖8.12 實心形狀
若要填充閉合的形狀,需要 Graphics 類的實例和 Brush。Graphics 類的實例提供方法,如 FillRectangle 和 FillEllipse,而 Brush 存儲填充的屬性,如顏色和模式。Brush 作為參數之一傳遞給填充方法。下面的代碼示例演示如何用純紅色填充橢圓。
SolidBrush mySolidBrush = new SolidBrush(Color.Red);
myGraphics.FillEllipse(mySolidBrush, 0, 0, 60, 40);
8.4.1 陰影畫筆
用陰影畫筆填充圖形時,要指定前景色、背景色和陰影樣式。前景色是陰影的顏色。
其格式為:
public HatchBrush (
HatchStyle hatchstyle,
Color foreColor,
Color backColor
)
hatchstyle,表示此 HatchBrush 所繪制的圖案。
foreColor,它表示此 HatchBrush 所繪制線條的顏色。
backColor,它表示此 HatchBrush 繪制的線條間空間的顏色。
例如:
HatchBrush myHatchBrush = new HatchBrush(HatchStyle.Vertical, Color.Blue, Color.Green);
GDI+ 提供 50 多種陰影樣式;在下面代碼繪制如圖8.13的實心形狀,顯示的三種樣式是:Horizontal、ForwardDiagonal 和 Cross。
Graphics g = this.CreateGraphics();
HatchBrush myHatchBrush1 =
new HatchBrush(HatchStyle.Horizontal, Color.Black, Color.Gray);
// Create rectangle for ellipse.
int x = 100;
int y = 100;
int width = 200;
int height = 100;
Rectangle rect1 = new Rectangle(x, y, width, height);
// Fill ellipse on screen.
g.FillEllipse(myHatchBrush1, rect1);
x = 320;
y = 100;
width = 200;
height = 100;
Rectangle rect2 = new Rectangle(x, y, width, height);
HatchBrush myHatchBrush2= new HatchBrush (HatchStyle.ForwardDiagonal, Color.Black, Color.Gray);
// Fill ellipse on screen.
g.FillEllipse(myHatchBrush2, rect2);
x = 520;
y = 100;
width = 200;
height = 100;
Rectangle rect3 = new Rectangle(x, y, width, height);
HatchBrush myHatchBrush3 =
new HatchBrush(HatchStyle.Cross, Color.Black, Color.Gray);
// Fill ellipse on screen.
g.FillEllipse(myHatchBrush3, rect3);
圖 8.13 繪制實心形狀
8.4.2 紋理畫筆
有了紋理畫筆,您就可以用位圖中存儲的圖案來填充圖形。
格式:
public TextureBrush (
Image bitmap
)
Bitmap為Image 對象,使用它來填充其內部。
例如,假定圖片存儲在名為 MyTexture.bmp 的磁盤文件中。
Image myImage = Image.FromFile("MyTexture.bmp");
TextureBrush myTextureBrush = new TextureBrush(myImage);
下面代碼用圖8.14片來填充橢圓,其效果如圖8.15:
圖 8.14 填充圖片
Graphics g = this.CreateGraphics();
//打開填充的圖片
Image myImage = Image.FromFile("e:\\text.jpg");
TextureBrush myTextureBrush = new TextureBrush(myImage);
g.FillEllipse(myTextureBrush, 100,100, 200, 100);
圖 8.15 用小圖片進行填充
Image myImage = Image.FromFile("MyTexture.bmp");
TextureBrush myTextureBrush = new TextureBrush(myImage);
8.4.3 漸變畫筆
GDI+ 提供兩種漸變畫筆:線性和路徑。您可以使用線性漸變畫筆來用顏色(在您橫向、縱向或斜向移過圖形時會逐漸變化的顏色)填充圖形。下面的代碼示例演示如何用水平漸變畫筆填充一個橢圓,當從橢圓的左邊緣向右邊緣移動時,畫筆顏色會由藍變為綠。
常用格式:
public LinearGradientBrush (
Rectangle rect,
Color color1,
Color color2,
LinearGradientMode linearGradientMode
)
rect指定線性漸變的界限。
color1 表示漸變起始色的 Color 結構。
color2 表示漸變結束色的 Color 結構。
linearGradientMode 為LinearGradientMode 枚舉元素,它指定漸變方向。漸變方向決定漸變的起點和終點。例如,LinearGradientMode.ForwardDiagonal 指定起始點是矩形的左上角,而結束點是矩形的右下角。
LinearGradientBrush myLinearGradientBrush = new LinearGradientBrush(
myRectangle,
Color.Blue,
Color.Green,
LinearGradientMode.Horizontal);
下面的代碼用從藍到綠的漸變填充橢圓,如圖8-16。
Graphics g = this.CreateGraphics();
Rectangle myRectangle = new Rectangle(100, 100, 200, 100);
LinearGradientBrush myLinearGradientBrush = new LinearGradientBrush(
myRectangle,
Color.Blue,
Color.Green,
LinearGradientMode.ForwardDiagonal);
g.FillEllipse(myLinearGradientBrush, 100, 100, 200, 100);
圖8.16 顏色漸變
8.5 繪制文本
到目前為止,本章還有一個非常重要的問題要討論—— 顯示文本。因為在屏幕上繪制文本通常比繪制簡單圖形更復雜。在不考慮外觀的情況下,只顯示一兩行文本是非常簡單的—— 它只需調用Graphics實例的一個方法Graphics.DrawString()。
格式:
public void DrawString (
string s,
Font font,
Brush brush,
PointF point
)
s 為要繪制的字符串。
font定義字符串的文本格式。
brush確定所繪制文本的顏色和紋理。
point,它指定所繪制文本的左上角。
下面代碼以16磅宋體及32磅黑體分別顯示你好,如圖8.17
Graphics g = this.CreateGraphics();
String drawString = "你好宋體";
// Create font and brush.
Font drawFont = new Font("宋體", 16);
SolidBrush drawBrush = new SolidBrush(Color.Black);
// Create point for upper-left corner of drawing.
PointF drawPoint = new PointF(150.0F, 150.0F);
// Draw string to screen.
g.DrawString(drawString, drawFont, drawBrush, drawPoint);
Font drawFont2 = new Font("黑體", 32);
SolidBrush drawBrush2 = new SolidBrush(Color.Gray);
// Create point for upper-left corner of drawing.
PointF drawPoint2 = new PointF(150.0F, 200.0F);
drawString = "你好黑體32";
// Draw string to screen.
g.DrawString(drawString, drawFont2, drawBrush2, drawPoint2);
圖 8-17 顯示字符
8.6 顏色對話框
顏色對話框用於顯示並設置用戶可用的顏色。如圖8.18
圖 8.18 顏色對話框
顏色對話框由ColorDialog類來實現。
其使用步驟為:
1 建立ColorDialog對象
ColorDialog MyDialog = new ColorDialog();
2 設置用可以自定義顏色
MyDialog.AllowFullOpen = true;
3 顯示對話框
if (MyDialog.ShowDialog() == DialogResult.OK)
{
…;
}
以下代碼用顏色對話框設置鋼筆和畫筆的顏色,並用於畫實心和空心橢圓,如圖8.19。
Graphics g = this.CreateGraphics();
//建立顏色對話框
ColorDialog MyDialog = new ColorDialog();
// 允許用戶自義顏色
MyDialog.AllowFullOpen = true;
MyDialog.ShowHelp = true;
//顯示顏色對話框
if (MyDialog.ShowDialog() == DialogResult.OK)
{
Pen pen = new Pen(MyDialog.Color, 3);
Brush brush = new SolidBrush(MyDialog.Color);
Rectangle rect1 = new Rectangle(100, 100, 200, 100);
Rectangle rect2 = new Rectangle(320, 100, 200, 100);
// 畫空心空心橢圓.
g.DrawEllipse(pen, rect1);
g.FillEllipse(brush, rect2);
}
圖 8.19 用自定義顏色畫的橢圓
8.7 鼠標事件
繪制直線需要獲取起點坐標、終點坐標,繪制矩形、橢圓需要獲取起點坐標及繪制的大小。這些坐標或大小可以從鍵盤輸入,但這不方便,也不符合用戶的習慣。因而,我們需要學習用鼠標事件。
事件是類在發生其關注的事情時用來提供通知的一種方式,是可以通過代碼響應或“處理”的操作。事件可由用戶操作(如單擊鼠標或按某個鍵)、程序代碼或系統生成。事件驅動的應用程序執行代碼以響應事件。每個窗體和控件都公開一組預定義事件,您可根據這些事件進行編程。如果發生其中一個事件並且在相關聯的事件處理程序中有代碼,則調用該代碼。
事件處理函數通常有兩個參數:
第一個參數為引用事件源的對象,第二個參數為與事件相關的數據。如:
private void button1_MMove ( object sender , System.Windows.Forms. MouseEventArgs e )。
常用的鼠標事件如表8.3
表8.3 常用的鼠標事件
| 鼠標事件 |
說明 |
| MouseDown |
當鼠標指針在控件上且用戶按下鼠標按鈕時發生此事件。此事件的處理程序接收類型為 MouseEventArgs 的參數。 |
| MouseMove |
當鼠標指針在控件上移動時發生此事件。此事件的處理程序接收類型為 MouseEventArgs 的參數。 |
| MouseUp |
當鼠標指針在控件上且用戶釋放鼠標按鈕時發生此事件。此事件的處理程序接收類型為 MouseEventArgs 的參數。 |
| Click |
釋放鼠標按鈕時發生此事件,通常發生在 MouseUp 事件前。此事件的處理程序接收類型為 EventArgs 的參數。如果只需要確定何時發生單擊,可處理此事件。 |
| DoubleClick |
雙擊控件時發生此事件。此事件的處理程序接收類型為 EventArgs 的參數。如果只需要確定何時發生雙擊,可處理此事件。 |
MouseEventArgs 的命名空間為System.Windows.Forms,它為 MouseUp、MouseDown 和 MouseMove 事件提供數據。
其常用的屬性如表8.4
表8.4 鼠標常用的屬性
| 名稱 |
說明 |
| 獲取曾按下的是哪個鼠標按鈕。 |
|
| 獲取按下並釋放鼠標按鈕的次數。 |
|
| 獲取鼠標在產生鼠標事件時的位置。 |
|
| 獲取鼠標在產生鼠標事件時的 x 坐標。 |
|
| 獲取鼠標在產生鼠標事件時的 y 坐標。 |
事件的編程通常分為兩個步驟
l 編寫事件處理的函數
l 把事件與處理函數關聯起來(Delegate)
對於MouseDown,MouseUp,MouseMove事件,其格式為:
"組件名稱"."事件名稱"+= new System.Windows.Forms. MouseEventHandler("事件名稱");
8.4.1 MouseMove
1) 編寫處理函數
假設我們已建立了名為Form1的視窗,我們可以在Form1的類中編寫如函數
private void Form1_OnMouseMove ( object sender , MouseEventArgs e )
{
this.Text = "當前鼠標的位置為:( " + e.X + " , " + e.Y + ")" ;
}
2)關聯事件和處理函數
在視窗的初始函數InitializeComponent中加入如下語句。
this.MouseMove += new System.Windows.Forms.MouseEventHandler(Form1_OnMouseMove);
8.4.2 MouseDown
1) 編寫處理函數
假設我們已建立了名為Form1的視窗,我們可以在Form1的類中編寫如函數
private void Form1_MouseDown ( object sender , MouseEventArgs e )
{
if ( e.Button == MouseButtons.Left )
MessageBox.Show ( "按動鼠標左鍵!" ) ;
if ( e.Button == MouseButtons.Middle )
MessageBox.Show ( "按動鼠標中鍵!") ;
if ( e.Button == MouseButtons.Right )
MessageBox.Show ( "按動鼠標右鍵!") ;
}
2)關聯事件和處理函數
在視窗的初始函數InitializeComponent中加入如下語句。
this.MouseMove += new System.Windows.Forms.MouseEventHandler(Form1_OnMouseMove);
8.8 應用實例
本實例用鼠標拖動繪制直線,空實心矩形,橢圓,並可以設置線型及填充類型。可以在第七章的基礎上增加此功能。
步驟(若在第七章的基礎上增加功能直接轉到步驟5):
1)建立圖像處理項目,名字為”Paint”。並把Form1的自動滾動屬性“AutoScroll”設置為ture
2) 在窗體上繪制 PictureBox 控件,其名字為“ pictureBox1”。
3)在Form1 類中增加一個成員變量,即
private Bitmap bitmap;
4) 建立“文件”菜單,在其屬性中名字改為“File”
5)在“文件“下建立“新建”選項,在其屬性中名字改為“NewFile_M“。
6)建立“繪圖”菜單,其名字為“Painting_M”,並在其上建立“直線”、“空心矩形”、“實心矩形”、“空心橢圓”及“實心橢圓”選項,在它們的屬性中名字分別改為“LineM”、“RectangleM”、“FillRectM”,“Ellipse_M”和“FillEllM”。
7)建立“顏色”菜單,其名字為“ColorM”,並在它上面建立“紅色”、“綠色”、 “藍色”及自定義顏色選項,其名字分別為“RedM”,“GreenM”,“BlueM”及“MyColor”。
8)建立工具欄:單擊工具箱中的“菜單及工具欄”,把“ToolStrip”拖入視窗。
9)增加一個按鈕:單擊新建的工具欄中的“增加ToolStripButton”按鈕,增加一個按鈕,並在屬性中為其改名,如改為“NewFile_T”。
10) 在“附件中的畫圖內”繪制工具欄按鈕的圖片,圖片的大小為16*16,如“新建”的圖片為 ,並保存圖片,例如文件名取為“newfile.bmp”
11) 改變工具欄按鈕的圖片,,在工具欄增加一個按鈕,並單擊其屬性中的“外觀”選項中的“image”選項中的”…”, 彈出“選擇資源”對話框,單擊“導入”按鈕,選擇顯示圖片。
12) 重復9)-11)步,直到為所有經常用的選項在工具建立對應的按鈕
13) 建立線型菜單,並在其下建立“線型”,“起始端點”,“終點端點”子菜單
14) 為線型建立 “Dash”,“DashDot”,“DashDotDot”,“Dot”,“Solid”子菜單
15) 為起始點建立“ArrowAnchor”,“DiamondAnchor”,“SquareAnchor”,“Triangle”,“RoundAnchor”子菜單
16) 為起始點建立“ArrowAnchor”,“DiamondAnchor”,“SquareAnchor”,“Triangle”,“RoundAnchor”子菜單
17) 雙擊“文件”菜單中的“新建”選項,系統自動為其建立響應函數的框架,在其中編寫程序,完成新建一個Bitmap圖像,並把它“綁定”在pictureBox11上。
private void New_Click(object sender, EventArgs e)
{
bitmap = new Bitmap(this.pictureBox1.Width, this.pictureBox1.Height);
this.pictureBox1.Image = bitmap;
}
18)雙擊工具欄“新建”按鈕,系統自動為其建立響應函數的框架,我們不必為其編寫新的代碼,只需要調用菜單中的“新建”選項的響應函數就行了。如下:
private void NewT_Click(object sender, EventArgs e)
{
New_Click( sender, e);
}
注:以后工具欄的代碼與此類似,即直接調用對應的菜單選項的處理函數。
19)在Form1 中增加成員數據pen,為Pen類,用於畫直線,空心矩陣,實心橢圓。
增加成員數brush,屬於Brush類,用於畫實心矩陣,實心矩陣,實心橢圓。
增加成員數據select,int 類型,用於存放選擇的繪圖方式。其值為1時,表示繪制直線,為2表示繪制空心矩形,為3表示繪制空心橢圓,為4表示繪制實心矩形,為5表示繪制空心矩形。
增加成員數據CanMove,為bool類型,用於判斷移動鼠標是否按着左鍵。
增加成員數據start,為Point類型,用於存放按下鼠標左鍵時鼠標的位置。
如下:
private Bitmap bitmap;
private Point start;
bool CanMove;
int select = 0;
Pen pen = new Pen(Color.Red, 2);
Brush brush = new SolidBrush(Color.Gray);
20) 雙擊菜單中的“直線”選項,為其編寫程序
private void LINE_Click(object sender, EventArgs e)
{
select = 1;
}
21) 雙擊菜單中的“空心矩形”選項,為其編寫程序
private void RECT_Click(object sender, EventArgs e)
{
select = 2;
}
22) 雙擊菜單中的“空心橢圓”選項,為其編寫程序
private void Ellipse_Click(object sender, EventArgs e)
{
select = 3;
}
23) 雙擊菜單中的“實心矩形”選項,為其編寫程序
private void FRect_Click(object sender, EventArgs e)
{
select = 4;
}
24)雙擊菜單中的“實空心橢圓”選項,為其編寫程序
private void FEll_Click(object sender, EventArgs e)
{
select = 5;
}
25) 雙擊菜單中的“紅色”選項,為其編寫程序
建立紅色的畫筆(Brush),及紅色的鋼筆(Pen)
private void RED_Click(object sender, EventArgs e)
{
pen = new Pen(Color.Red, float.Parse(this.linesize.Text));
brush=new SolidBrush(Color.Red);
}
26) 雙擊菜單中的“綠色”選項,為其編寫程序
建立綠色的畫筆(Brush),及綠色的鋼筆(Pen)
private void GREE_Click(object sender, EventArgs e)
{
pen = new Pen(Color.Green, float.Parse(this.linesize.Text));
brush = new SolidBrush(Color.Green);
}
27) 雙擊菜單中的“藍色”選項,為其編寫程序
建立藍色的畫筆(Brush),及藍色的鋼筆(Pen)
private void BLUE_Click(object sender, EventArgs e)
{
pen = new Pen(Color.Blue, float.Parse(this.linesize.Text));
brush = new SolidBrush(Color.Blue);
}
28) 雙擊“自定義顏色”選項,並為其編寫程序
private void ColorSet_Click(object sender, EventArgs e)
{
ColorDialog MyDialog = new ColorDialog();
// Keeps the user from selecting a custom color.
MyDialog.AllowFullOpen = true;
// Allows the user to get help. (The default is false.)
MyDialog.ShowHelp = true;
// Sets the initial color select to the current text color.
// MyDialog.Color = textBox1.ForeColor;
// Update the text box color if the user clicks OK
if (MyDialog.ShowDialog() == DialogResult.OK)
{
pen = new Pen(MyDialog.Color,float.Parse(this.linesize.Text));
brush = new SolidBrush(MyDialog.Color);
}
}
29) 為鼠標移動編寫處理程序
當變量CanMove為True時,已獲取了繪制圖形的初始位置,但終止位置或大小還沒有確定,因而假設當位置為終止位置,動態地繪制圖形。Start為第一次按下鼠標左鍵時鼠標的位置,即繪制圖形的初始位置。e.x, e.y為當前鼠標的位置,繪制圖形的終止位置。因而顯然,e.X - start.X 為繪制圖像的寬度,e.y-start.y為繪制圖像的高度。Select為繪畫的方式,1為真線,2為空心矩形,3為空心橢圓,4為實心矩形,5為實心橢圓。
private void Form1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (this.CanMove == true)
{
this.pictureBox1.Image = (Bitmap)this.bitmap.Clone();
Graphics g = Graphics.FromImage(this.pictureBox1.Image);
switch(select){
case 1:
g.DrawLine(pen, this.start, new Point(e.X, e.Y));//重繪
break;
case 2:
if (start.X<e.X&&start.Y<e.Y)
g.DrawRectangle(pen, start.X,start.Y, e.X-start.X,e.Y-start.Y);
break;
case 3:
if (start.X < e.X && start.Y < e.Y)
g.DrawEllipse(pen, start.X, start.Y, e.X - start.X, e.Y - start.Y);
break;
case 4:
if (start.X < e.X && start.Y < e.Y)
g.FillRectangle(brush, start.X, start.Y, e.X - start.X, e.Y - start.Y);
break;
case 5:
if (start.X < e.X && start.Y < e.Y)
g.FillEllipse(brush, start.X, start.Y, e.X - start.X, e.Y - start.Y);
break;
}
g.Dispose();
}
this.MousePos.Text = "坐標" + e.X + "," + e.Y;
}
30) 關聯鼠標移動事件和處理程序
在Form1類中的InitializeComponent成員函數增加如下語句:
this.pictureBox1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.Form1_MouseMove);
因為圖形是畫在pictureBox1控件上的,因而當鼠標在pictureBox1上移動時會觸發鼠標處理函數。
31)為鼠標按左鍵編寫處理程序為
當canMove為false時,說明是剛按下鼠標左鍵,因而用this.start = new Point(e.X, e.Y);語句保存畫圖的起始點位置,並把canMove設置為true,因而鼠標移動時會動態地畫圖形。以后當再一次按下鼠標左鍵時,獲得圖形的終止位置,因而繪制圖形,並把canMove設置為false, 鼠標移動時不再畫圖形。
private void Form1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (!CanMove)
{
this.start = new Point(e.X, e.Y);
this.CanMove = true;
}
else
{
this.pictureBox1.Image = this.bitmap;
Graphics g = Graphics.FromImage(this.pictureBox1.Image);
switch(select){
case 1:
g.DrawLine(pen, this.start, new Point(e.X, e.Y));
break;
case 2:
if (start.X < e.X && start.Y < e.Y)
g.DrawRectangle(pen, start.X, start.Y, e.X - start.X, e.Y – 盤start.Y);
break;
case 3:
if (start.X < e.X && start.Y < e.Y)
g.DrawEllipse(pen, start.X, start.Y, e.X - start.X, e.Y - start.Y);
break;
case 4:
if (start.X < e.X && start.Y < e.Y)
g.FillRectangle(brush, start.X, start.Y, e.X - start.X, e.Y - start.Y);
break;
case 5:
if (start.X < e.X && start.Y < e.Y)
g.FillEllipse(brush, start.X, start.Y, e.X - start.X, e.Y - start.Y);
break;
}
g.Dispose();
CanMove = false;
//this.pictureBox1.Invalidate();
}
}
}
32)-36)設置線的類型
32) 雙擊“Dash”選項,並為其編寫腳本
private void Dash_Click(object sender, EventArgs e)
{
pen.DashStyle = DashStyle.Dash;
}
33) 雙擊“DashDot ”選項,並為其編寫腳本
private void DashDot_Click(object sender, EventArgs e)
{
pen.DashStyle = DashStyle.DashDot;
}
34) 雙擊“DashDotDot 選項,並為其編寫腳本
private void DashDotDot_Click(object sender, EventArgs e)
{
pen.DashStyle = DashStyle.DashDotDot;
}
35) 雙擊“Dot 選項,並為其編寫腳本
private void Dot_Click(object sender, EventArgs e)
{
pen.DashStyle = DashStyle.Dot;
}
36) 雙擊“Solid ” 選項,並為其編寫腳本
private void Solid _Click(object sender, EventArgs e)
{
pen.DashStyle =DashStyle.Solid
}
37)-40)為線的起始端點設置類型
37) 雙擊“ArrowAnchor” 選項,並為其編寫腳本
private void ArrowAnchor_Click(object sender, EventArgs e)
{
pen.StartCap = LineCap. ArrowAnchor;
}
38)雙擊“DiamondAnchor” 選項,並為其編寫腳本
private void DiamondAnchor _Click(object sender, EventArgs e)
{
pen.StartCap = LineCap.DiamondAnchor;
}
39) 雙擊“squareAnchor” 選項,並為其編寫腳本雙擊
private void squareAnchor_Click(object sender, EventArgs e)
{
pen.StartCap = LineCap.SquareAnchor;
}
40)雙擊“triangle” 選項,並為其編寫腳本雙擊
private void triangle_Click(object sender, EventArgs e)
{
pen.StartCap = LineCap.Triangle;
}
41)-45)為為線的終止端點設置類型
41) 雙擊“ArrowAnchorEnd” 選項,並為其編寫腳本雙擊
private void ArrowAnchorEnd_Click(object sender, EventArgs e)
{
pen.EndCap = LineCap.DiamondAnchor;
}
42) 雙擊“DiamondAnchorEnd” 選項,並為其編寫腳本雙擊
private void DiamondAnchorEnd_Click(object sender, EventArgs e)
{
pen.EndCap = LineCap.DiamondAnchor;
}
43) 雙擊“RoundAnchorEnd” 選項,並為其編寫腳本雙擊
private void RoundAnchorEnd_Click(object sender, EventArgs e)
{
pen.EndCap = LineCap.RoundAnchor;
}
44) 雙擊“squareAnchorEnd” 選項,並為其編寫腳本雙擊
private void squareAnchorEnd_Click(object sender, EventArgs e)
{
pen.EndCap = LineCap.SquareAnchor;
}
45) 雙擊“TriangleEnd” 選項,並為其編寫腳本雙擊
private void TriangleEnd_Click(object sender, EventArgs e)
{
pen.EndCap = LineCap.Triangle;
}
本章小結
本章介紹用GDI+繪制圖形。主要包括:畫筆、鋼筆的基本概念,如何繪制直線、空心方框、橢圓、多邊形以及如何繪制實心的方框、橢圓、多邊形,鋼筆線的粗細、實線、虛線、起點及終點的設置,畫筆的填充方式等。在最后,我們在第七章的基礎上,綜合運用我們所學的知識,編寫一個簡單衫的畫圖程序。
一 基本概念
鋼筆 用於繪制線條圖案,它可以設置線的粗細、類型、起點終點的類型。
畫筆 用於實心的圖形,它可以設置不同的填充方式。
Point 圖像上的點
Size 表示大小
Rectangle 表示矩形區域
二 基本操作
DrawLine 繪制直線
DashStyle Pen的屬性,用於設置虛線類型
StartCap Pen的屬性,用於設置起始端點的類型
EndCap Pen的屬性,用於設置終點端點的類型
DrawRectangle 繪制空心矩形
FillRectangle 繪制實心矩形
DrawEllipse繪制空心橢圓
DrawArc 繪制圓弧
FillEllipse 繪制實心橢圓
DrawPolygon 繪制空心多邊形
FillPolygon繪制實心多邊形
HatchBrush 設置陰影畫筆
TextureBrush設置紋理畫筆
LinearGradientBrush 設置漸變畫筆
