C# GDI+ 绘制图像
原文: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 鼠标常用的属性
名称
说明
Button
获取曾按下的是哪个鼠标按钮。
Clicks
获取按下并释放鼠标按钮的次数。
Location
获取鼠标在产生鼠标事件时的位置。
X
获取鼠标在产生鼠标事件时的 x 坐标。
Y
获取鼠标在产生鼠标事件时的 y 坐标。
事件的编程通常分为两个步骤
l 编写事件处理的函数
l 把事件与处理函数关联起来(Delegate)
对于MouseDown,MouseUp,MouseMove事件,其格式为:
“组件名称”.“事件名称”+= new System.Windows.Forms. MouseEventHandler(“事件名称”);
8.4.1 MouseMove
- 编写处理函数
假设我们已建立了名为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
- 编写处理函数
假设我们已建立了名为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
- 在窗体上绘制 PictureBox 控件,其名字为“ pictureBox1”。
3)在Form1 类中增加一个成员变量,即
private Bitmap bitmap;
- 建立“文件”菜单,在其属性中名字改为“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”。
-
在“附件中的画图内”绘制工具栏按钮的图片,图片的大小为16*16,如“新建”的图片为 ,并保存图片,例如文件名取为“newfile.bmp”
-
改变工具栏按钮的图片,,在工具栏增加一个按钮,并单击其属性中的“外观”选项中的“image”选项中的”…”, 弹出“选择资源”对话框,单击“导入”按钮,选择显示图片。
-
重复9)-11)步,直到为所有经常用的选项在工具建立对应的按钮
13) 建立线型菜单,并在其下建立“线型”,“起始端点”,“终点端点”子菜单
- 为线型建立 “Dash”,“DashDot”,“DashDotDot”,“Dot”,“Solid”子菜单
15) 为起始点建立“ArrowAnchor”,“DiamondAnchor”,“SquareAnchor”,“Triangle”,“RoundAnchor”子菜单
16) 为起始点建立“ArrowAnchor”,“DiamondAnchor”,“SquareAnchor”,“Triangle”,“RoundAnchor”子菜单
-
双击“文件”菜单中的“新建”选项,系统自动为其建立响应函数的框架,在其中编写程序,完成新建一个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);
-
双击菜单中的“直线”选项,为其编写程序
private void LINE_Click(object sender, EventArgs e) { select = 1; }
-
双击菜单中的“空心矩形”选项,为其编写程序
private void RECT_Click(object sender, EventArgs e) { select = 2; }
-
双击菜单中的“空心椭圆”选项,为其编写程序
private void Ellipse_Click(object sender, EventArgs e) { select = 3; }
-
双击菜单中的“实心矩形”选项,为其编写程序
private void FRect_Click(object sender, EventArgs e)
{ select = 4; }
24)双击菜单中的“实空心椭圆”选项,为其编写程序
private void FEll_Click(object sender, EventArgs e)
{
select = 5;
}
- 双击菜单中的“红色”选项,为其编写程序
建立红色的画笔(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);
}
- 双击菜单中的“绿色”选项,为其编写程序
建立绿色的画笔(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);
}
- 双击菜单中的“蓝色”选项,为其编写程序
建立蓝色的画笔(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);
}
-
双击“自定义颜色”选项,并为其编写程序
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;
}
- 关联鼠标移动事件和处理程序
在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)设置线的类型
-
双击“Dash”选项,并为其编写脚本
private void Dash_Click(object sender, EventArgs e) { pen.DashStyle = DashStyle.Dash; }
-
双击“DashDot ”选项,并为其编写脚本
private void DashDot_Click(object sender, EventArgs e)
{ pen.DashStyle = DashStyle.DashDot;
}
-
双击“DashDotDot 选项,并为其编写脚本
private void DashDotDot_Click(object sender, EventArgs e)
{ pen.DashStyle = DashStyle.DashDotDot; }
-
双击“Dot 选项,并为其编写脚本
private void Dot_Click(object sender, EventArgs e) { pen.DashStyle = DashStyle.Dot; }
-
双击“Solid ” 选项,并为其编写脚本
private void Solid _Click(object sender, EventArgs e) { pen.DashStyle =DashStyle.Solid }
37)-40)为线的起始端点设置类型
-
双击“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;
}
- 双击“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)为为线的终止端点设置类型
-
双击“ArrowAnchorEnd” 选项,并为其编写脚本双击
private void ArrowAnchorEnd_Click(object sender, EventArgs e) { pen.EndCap = LineCap.DiamondAnchor; }
-
双击“DiamondAnchorEnd” 选项,并为其编写脚本双击
private void DiamondAnchorEnd_Click(object sender, EventArgs e)
{ pen.EndCap = LineCap.DiamondAnchor; }
-
双击“RoundAnchorEnd” 选项,并为其编写脚本双击
private void RoundAnchorEnd_Click(object sender, EventArgs e)
{ pen.EndCap = LineCap.RoundAnchor; }
-
双击“squareAnchorEnd” 选项,并为其编写脚本双击
private void squareAnchorEnd_Click(object sender, EventArgs e)
{
pen.EndCap = LineCap.SquareAnchor;
}
- 双击“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 设置渐变画笔