原文: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 设置渐变画笔