GDI+的中心就是Graphics对象,由Graphics类来表示,这个类定义了绘制和填充图形对象的方法和属性。所以嘛,Graphics类的方法和属性就显得相当重要了。
Graphics类的属性(字段)很多,具体就请翻看MSDN好了。
Graphics类的方法分为三类:绘制、填充及其他。
绘制方法
Graphics类的绘制方法用于绘制直线、曲线及封闭曲线与图像的外边界。
l 绘制直线(DrawLine方法)
用于在由坐标对指定的两个点之间绘制一条直线。例如:
// 用四种颜色和不同宽度创建四个Pen对象 Pen redPen = new Pen(Color.Red, 1); Pen bluePen = new Pen(Color.Blue, 2); Pen greenPen = new Pen(Color.Green, 3); Pen blackPen = new Pen(Color.Black, 4); Graphics g = this.CreateGraphics(); //g.SmoothingMode = SmoothingMode.AntiAlias; // 使用浮点坐标绘制直线 float x1 = 20.0F, y1 = 20.0F; float x2 = 200.0F, y2 = 20.0F; g.DrawLine(redPen, x1, y1, x2, y2); // 使用Point结构体绘制直线 Point pt1 = new Point(20, 20); Point pt2 = new Point(20, 200); g.DrawLine(greenPen, pt1, pt2); // 使用PointF结构体绘制直线 PointF ptf1 = new PointF(20.0F, 20.0F); PointF ptf2 = new PointF(200.0F, 200.0F); g.DrawLine(bluePen, ptf1, ptf2); // 使用整数坐标绘制直线 int X1 = 60, Y1 = 40, X2 = 250, Y2 = 100; g.DrawLine(blackPen, X1, Y1, X2, Y2); // 释放对象 redPen.Dispose(); bluePen.Dispose(); greenPen.Dispose(); blackPen.Dispose(); |
l 绘制相连的直线(DrawLines方法)
绘制相连的直线,可以通过多次调用DrawLine方法来完成,也可以使用DrawLines方法。它需要Point或者PointF类型的数组来作为参数。
Pen redPen = new Pen(Color.Red, 1); PointF[] ptsArray = { new PointF(20.0F,20.0F), new PointF(20.0F,200.0F), new PointF(200.0F,200.0F), new PointF(20.0F,20.0F) }; Graphics g = this.CreateGraphics(); g.DrawLines(redPen, ptsArray); |
l 绘制矩形(DrawRectangle、DrawRectangles)
只需要指定矩形的起始点、高和宽即可,当然,不要忘记选择笔型。用DrawRectangels可以画出一组矩形来。
// 创建钢笔和点 Pen redPen = new Pen(Color.Red, 1); Pen bluePen = new Pen(Color.Blue, 2); Pen greenPen = new Pen(Color.Green, 3); float x = 5.0F, y = 5.0F; float width = 100.0F; float height = 200.0F; Graphics g = this.CreateGraphics(); // 创建矩形 Rectangle rect = new Rectangle(20, 20, 80, 40); // 绘制矩形 g.DrawRectangle(bluePen, x, y, width, height); g.DrawRectangle(redPen, 60, 80, 140, 50); g.DrawRectangle(greenPen, rect); // 释放对象 redPen.Dispose(); bluePen.Dispose(); greenPen.Dispose(); g.Dispose(); |
l 绘制圆和椭圆(DrawEllipse)
看看示例,共有四种不同的重载方法可供选择。
// 创建钢笔和点 Pen redPen = new Pen(Color.Red, 6); Pen bluePen = new Pen(Color.Blue, 4); Pen greenPen = new Pen(Color.Green, 2); Graphics g = this.CreateGraphics(); // 创建矩形 Rectangle rect = new Rectangle(80, 80, 50, 50); // 绘制椭圆 g.DrawEllipse(greenPen, 100.0F, 100.0F, 10.0F, 10.0F); g.DrawEllipse(redPen, rect); g.DrawEllipse(bluePen, 60, 60, 90, 90); g.DrawEllipse(greenPen, 40.0F, 40.0F, 130.0F, 130.0F); redPen.Dispose(); bluePen.Dispose(); greenPen.Dispose(); |
可以把它看成是指定了外接矩形的椭圆,当其长、短轴相等的时候就是一个圆。很遗憾的是没有提供诸如离心率来画椭圆(要求好像高了些,hoho)。
l 绘制文本(DrawString)
利用DrawString方法可以在图形表面上绘制一个文本字符串,可以指定文本内容、字体、画笔和文本的起始点等。
// 创建画笔 SolidBrush blueBrush = new SolidBrush(Color.Blue); SolidBrush redBrush = new SolidBrush(Color.Red); SolidBrush greenBrush = new SolidBrush(Color.Green); // 创建矩形 Rectangle rect = new Rectangle(20, 20, 200, 100); // 要绘制的文本 string drawString = "Rain(R) Studio!"; // 创建Font对象 Font drawFont = new Font("Verdana", 14); float x = 100.0F; float y = 100.0F; Graphics g = this.CreateGraphics(); // 字符串格式 StringFormat drawFormat = new StringFormat(); // 将字符串格式标记设置为垂直方向 drawFormat.FormatFlags = StringFormatFlags.DirectionVertical; // 绘制字符串 g.DrawString("Drawing text", new Font("Tahoma", 14), greenBrush, rect); g.DrawString(drawString, new Font("Arial", 12), redBrush, 120, 140); g.DrawString(drawString, drawFont, blueBrush, x, y, drawFormat); // 释放对象 blueBrush.Dispose(); redBrush.Dispose(); greenBrush.Dispose(); drawFont.Dispose(); g.Dispose(); |
l 绘制圆弧(DrawArc)
其实这里能够绘制的不仅仅是圆弧,也可以是椭圆的一段弧。其方法的一个重载是这样的:
e.Graphics.DrawArc(redPen, rect, startAngle, sweepAngle);
指定画笔、椭圆的外接矩形,起始角和扫过角度。这里的“角度”采用角度制(360度圆周)而非弧度制。起始点在椭圆的最右边,扫过的角度按照顺时针计算。如果超过360度,那就没有意义了,总是可以看见一个完整的椭圆。
l 绘制曲线(DrawCurve)
一般的方法是指定曲线上的几个点,然后通过张力定出一根曲线来。
Graphics g = this.CreateGraphics(); Pen bluePen = new Pen(Color.Blue, 1); // 创建点的数组 PointF pt1 = new PointF(40.0f, 50.0f); PointF pt2 = new PointF(50.0f, 75.0f); PointF pt3 = new PointF(100.0f, 115.0f); PointF pt4 = new PointF(200.0f, 180.0f); PointF pt5 = new PointF(200.0f, 90.0f); PointF[] ptsArray = { pt1,pt2,pt3,pt4,pt5 }; // 绘制曲线 g.DrawCurve(bluePen, ptsArray); bluePen.Dispose(); g.Dispose(); |
如果要画封闭曲线则用DrawClosedCurve,具体请参考MSDN
l 贝塞尔曲线(DrawBezier、DrawBeziers)
一条贝塞尔曲线由四个点定义:两个端点和两个控制点。Graphics类提供了描绘它们的两个方法,单根曲线和一组曲线。
Graphics g = this.CreateGraphics(); Pen bluePen = new Pen(Color.Blue, 1); Pen redPen = new Pen(Color.Red, 1); PointF p1 = new PointF(40.0f, 50.0f); PointF p2 = new PointF(60.0f, 70.0f); PointF p3 = new PointF(80.0f, 34.0f); PointF p4 = new PointF(120.0f, 180.0f); PointF p5 = new PointF(200.0f, 150.0f); PointF p6 = new PointF(350.0f, 250.0f); PointF p7 = new PointF(200.0f, 200.0f); PointF[] ptsArray = { p1,p2,p3,p4,p5,p6,p7 }; // 绘制贝塞尔曲线 g.DrawBezier(bluePen, 30, 20, 80, 60, 120, 180, 140, 50); // 多条贝塞尔曲线 g.DrawBeziers(redPen, ptsArray); redPen.Dispose(); bluePen.Dispose(); g.Dispose(); |
l 绘制多边形(DrawPolygon)
指定多边形的几个顶点,然后就可以画出这个多边形。
Graphics g = this.CreateGraphics(); Pen greenPen = new Pen(Color.Green, 1); PointF p1 = new PointF(40.0f, 50.0f); PointF p2 = new PointF(60.0f, 70.0f); PointF p3 = new PointF(80.0f, 34.0f); PointF p4 = new PointF(120.0f, 180.0f); PointF p5 = new PointF(200.0f, 150.0f); PointF[] ptsArray = { p1,p2,p3,p4,p5 }; g.DrawPolygon(greenPen, ptsArray); greenPen.Dispose(); g.Dispose(); |
l 绘制图标(DrawIcon、DrawIconUnstretched)
DrawIcon方法在指定坐标出绘制一个由指定对象表示的图标,并根据需要拉伸图标;后一种方法不缩放图标。
Graphics g = this.CreateGraphics(); Icon icon1 = new Icon(@"d:\zqustc\ico\bmw.ico"); Icon icon2 = new Icon(@"d:\zqustc\ico\explorer.ico"); int x = 20; int y = 50; g.DrawIcon(icon1,x, y); Rectangle rect = new Rectangle(100, 200, 400, 400); g.DrawIconUnstretched(icon2, rect); |
l 绘制路径(DrawPath)
图形路径,就是多个图形的组合,GraphicsPath类是定义在System.Drawing.Drawing2D命名空间中的。绘制图形路径的时候,先要创建一个GraphicsPath对象,然后通过调用这个对象的Add系列方法,把我们需要的图形加入到这个路径当中去。
Graphics g = this.CreateGraphics(); Pen greenPen = new Pen(Color.Green, 1); // 创建一个图形路径 GraphicsPath path = new GraphicsPath(); // 将一条直线添加到此路径 path.AddLine(20, 20, 103, 80); // 将一个椭圆添加到此路径 path.AddEllipse(100, 50, 100, 100); // 添加另三条直线 path.AddLine(195, 80, 300, 80); path.AddLine(200, 100, 300, 100); path.AddLine(195, 120, 300, 120); // 创建矩形并加入路径 Rectangle rect = new Rectangle(50, 150, 300, 50); path.AddRectangle(rect); // 绘制路径 g.DrawPath(greenPen, path); g.Dispose(); greenPen.Dispose(); |
l 绘制扇形(DrawPie)
同前面绘制Arc的方法类似,只不过多了两条从原点到端点的线段把整个图形封闭起来而已。角度的定义和使用方法与Arc相同。
Graphics g=this.CreateGraphics(); g.Clear(this.BackColor); float startAngle = (float)Convert.ToDouble(textBox1.Text); float sweepAngle = (float)Convert.ToDouble(textBox2.Text); Pen bluePen = new Pen(Color.Blue, 1); g.DrawPie(bluePen, 20, 20, 100, 100, startAngle, sweepAngle); bluePen.Dispose(); g.Dispose(); |
这里还演示了如何从TextBox中获取数字的方法。在C#中这变得相当简单,Convert类里面有强大的类型转换方法,一般来说,除非这里没有提供方法(比如double到float的转换),不要使用强制类型转换这种土方法。
l 绘制图像(DrawImage、DrawImageUnscaled)
后者与前者的不同就在于后者不会对图像进行缩放。
下面这段程序使用Image类的静态方法FromFile()来创建Image对象,注意一下这里的异常处理技巧。
Graphics g=this.CreateGraphics(); try { Image newImage = Image.FromFile(@"d:\zqustc\ico\lena.bmp"); g.DrawImage(newImage, this.ClientRectangle); newImage.Dispose(); } catch (Exception ex) { MessageBox.Show(ex.Message); } finally { g.Dispose(); } |
填充方法
Graphics类的钢笔(Pen)用于绘制图形的外边界,而画笔(Brush)用于填充图形的内部。Graphics可用的填充方法很有限,我们只能填充特定的图形。
发现原先那样贴代码很是累,下面除非很有价值的例子,我就不把调试的程序放上来了。毕设时间很少,效率第一啊。。
l FillClosedCurve方法,用于填充封闭曲线的内部。这里要提一下它的一个参数——填充模式(FillMode),这是一个枚举,可以设定交替模式或者环绕模式。只有当Curve存在自身相交的情况下才需要使用填充模式。
例:g.FillClosedCurve(blueBrush, ptsArray, FillMode.Alternate, tension);
l FillEllipse方法,填充一个椭圆的内部。用法和DrawEllipse类似,只是注意Pen要改成Brush。
例:g.FillEllipse(blueBrush, 40.0f, 40.0f, 130.0f, 130.0f );
l FillPath方法,填充图形路径的内部。同前面DrawPath一样,也是需要先建立GraphicsPath类,将路径add进去,随后再调用FillPath填充。
l FillPie方法,填充扇形区域。Arc本来就只有一条曲线,也就不存在填充了。
例:g.FillPie(new SolidBrush(Color.Red), 0.0f, 0.0f, 100, 60, 0.0f, 90.0f);
l FillPolygon方法,填充多边形。此方法使用的参数有三个:画笔、点数组和填充模式。
例:g.FillPolygon(greenBrush, ptsArray);
l FillRectangle方法,填充矩形区域。
例:g.FillRectangle(new HatchBrush(HatchStyle.BackwardDiagonal, Color.Yellow, Color.Black), rect);
l FillRegion方法,使用画笔填充指定的区域。
Graphics类的其它方法
Graphics类还有一些杂项方法,可以处理相关事务。
l Clear方法,清除整个绘图表面,并使用指定的背景色填充绘图表面,参数是一个Color类型的变量。清除窗体:
g.Clear(this.BackColor);
传递该窗体的背景色;
l MeasureString方法,测量使用Font对象绘制的字符串,并且返回一个SizeF值。此外,这个方法还可以确定字符串中的字符总数和线条总数。
具体的例子:
Graphics g = Graphics.FromHwnd(this.Handle); g.Clear(this.BackColor); string testString = "Rain(R) Studio"; Font verdana14 = new Font("Verdana", 14); Font tahoma18 = new Font("Tahoma", 18); int nChars; int nLines; // 调用MeasureString 来测量字符串 SizeF sz = g.MeasureString(testString, verdana14); string stringDetails = "Height: " + sz.Height.ToString() + ", Width: " + sz.Width.ToString(); MessageBox.Show("First string details: " + stringDetails); g.DrawString(testString, verdana14, Brushes.Green, new PointF(0, 100)); g.DrawRectangle(new Pen(Color.Red, 2), 0.0f, 100.0f, sz.Width, sz.Height); sz = g.MeasureString("Ellipse", tahoma18, new SizeF(0.0f, 100.0f), new StringFormat(), out nChars, out nLines); stringDetails = "Height: " + sz.Height.ToString() + ", Width: " + sz.Width.ToString() + ", Lines: " + nLines.ToString() + ", Chars: " + nChars.ToString(); MessageBox.Show("Second string details: " + stringDetails); g.DrawString("Ellipse", tahoma18, Brushes.Blue, new PointF(10.0f, 10.0f)); g.DrawEllipse(new Pen(Color.Red, 3), 10, 10, sz.Width, sz.Height); g.Dispose(); |
l FromImage、FromHdc和FromHwnd方法,能够从不同的对象来创建Graphics。