上篇博客说了些题外话,为什么偏偏在这时候讨论事件和委托。对于事件和委托是.NET程序猿必须掌握的一堂课,是程序猿踏入设计而不是编写的里程碑,了解了事件的形成就能够使用代码编写动态创建的事件,而学会了委托才能真正的踏入设计的阶段。
好了回到我们文章的正题,从番外篇回来要开始我们GDI+的旅程啦,今天我们对GDI+的基本架构屡屡,并利用GDI+的几个基本的类来绘制一个圆柱形,重点在于通过实例来区分Graphics和GraphicsPath两个类之间的关系。
GDI+常用类的划分,通过下图你还不能了解GDI+的奥秘,好戏在后头……
也许你要问为什么会有Graphics和GraphicsPath两种类的划分,是啊为什么呢?要从根本上区分两者,首先要看它们的作用,Graphics是在System.Drawing命名空间下的一个类,主要用于图形界面的显示,另外也封装了多种图形的绘制方法,而且还包括了图形的剪辑。
接着来看GraphicsPath类,该类和Graphics类最大的区别是两者分属的命名空间不同,GraphicsPath类是System.Drawing.Drawing2D命名空间下的类,提供了一系列相互连接的直线和曲线,它在绘图功能比Graphics类更优,而且灵活。
Note:图形剪辑功能是使用Graphics类SetClip方法实现的,而GraphicsPath类只封装了基本图形的绘制,它没有提供显示和剪辑的方法。
为什么会有两种Brush类和SolidBrush类颜色类?因为SolidBrush是Brush类的一个子类,Brush是一个抽象类,所以在具体的方法中使用时只能通过实例化SolidBrush类来实现颜色的填充。
相同Bitmap和image也是一种父子关系,Bitmap继承了抽象的父类image,为用户提供了处理由像素数据定义的图像。
Note:在编程时,我们往往把需要把绘制的图像保存在一个Bitmap对象中,使图像保持不变。
这里为什么要说区域类,它并不属于图形绘制类,是的它指定了一个路径区域,使得我们可以对区域进行操作,灵活的使用该类可以在原图中获取我们想要的区域,另外也提供了区域的放大和缩放等功能。
Note:它和Graphics和GraphicsPath类一起使用可以获得想要的区域。
上面把常用的GDI+编程中使用的类分类汇总了下, 但有些类没有涉及到,如 Rectangle 和 Point 等类可封装 GDI+ 基元, Pen 类用于绘制直线和曲线。
Note:为什么说Pen类绘制直线和曲线而不是Graphics和GraphicsPath中的方法?因为,在方法中指定了具体绘画的过程,真正实现绘画的是Pen类,它指定了绘制线的样式。
上面我们总结了几种类,接下来做一个实例,使用GDI+绘制一个圆柱形,在实战中深入体会几种类的使用方法。
绘制思路:首先使用GraphicsPath类来绘制一个闭合的图形,然后绘制圆柱的上底和下底的椭圆。
清单一:绘制圆柱的闭合区域,使用GraphicsPath类绘制闭合区域,并使用CloseFigure方法闭合该区域,最后使用Graphics类来填充显示该区域。
private void DrawClosedFigure(PaintEventArgs e) { Graphics g = e.Graphics; GraphicsPath gp = new GraphicsPath(); Point p = new Point(20, 20); //矩形所在的正方形的起始点坐标 Size s = new Size(540, 380); //圆柱所在的正方形的大小 float flaHeight = (float)s.Width / (float)6.75; //获取上方椭圆的高 float flaRecHeight = (float)s.Height / (float)2.62; //获取上方椭圆所在矩形的高的一半 int intHeight = Convert.ToInt16(Math.Round(flaHeight, 0)); int intRecHeight = Convert.ToInt16(Math.Round(flaRecHeight, 0)); Rectangle rect = new Rectangle(p, s); //创建一个矩形区域,用来绘制圆柱 gp.AddArc(rect.X, rect.Y + intHeight, s.Width, intRecHeight, 180, 180); //绘制圆柱形的上半圆 gp.AddArc(rect.X, rect.Y + rect.Height, s.Width, intRecHeight, 0, 180); //绘制圆柱形的下半圆 gp.CloseFigure(); //闭合该区域 g.SmoothingMode = SmoothingMode.HighQuality; //设置边框圆滑 g.DrawPath(new Pen(Color.FromArgb(213, 204, 186), 6), gp); //在绘画板上绘制该画板区域,绘制出想要的边界 g.FillPath(new SolidBrush(Color.FromArgb(245, 237, 229)), gp); //填充画板区域的内部 }
private void DrawBottom(PaintEventArgs e) { Graphics g = e.Graphics; Point p = new Point(20, 20); //矩形所在的正方形的起始点坐标 Size s = new Size(540, 380); //圆柱所在的正方形的大小 float flaHeight = (float)s.Width / (float)6.75; //获取上方椭圆的高 float flaRecHeight = (float)s.Height / (float)2.62; //获取上方椭圆所在矩形的高的一半 int intHeight = Convert.ToInt16(Math.Round(flaHeight, 0)); int intRecHeight = Convert.ToInt16(Math.Round(flaRecHeight, 0)); Rectangle rect = new Rectangle(p, s); //创建一个矩形区域,用来绘制圆柱 g.FillEllipse(new SolidBrush(Color.FromArgb(213, 204, 186)), rect.X - 2, rect.Y + rect.Height, s.Width + 3, intRecHeight); //绘制圆柱形的底 g.DrawArc(new Pen(Color.FromArgb(213, 204, 186), 3), new Rectangle(rect.X, rect.Y + intHeight, s.Width, intRecHeight), 170, 10); //绘制圆柱形上底出来的左边 g.DrawArc(new Pen(Color.FromArgb(213, 204, 186), 3), new Rectangle(rect.X, rect.Y + intHeight, s.Width, intRecHeight), 0, 10); //绘制圆柱形上底出来的右边 }上面的绘制方法最重要的部分没有说明,是关于圆柱的高和底的椭圆比的问题,这个比值相当重要,有了这个比值绘制出来的椭圆才美观……
上文中从GDI+的基础出发,汇总了GDI+编程过程中常用的几种类,通过分类能够使我们更加清晰的分清几种类的用法,能达到灵活的使用几种类来创建图形。另外还有多实践,在实战中深刻的体会它们之间的用法,这样才能做到游刃有余。