GDI+学习笔记2
(三) GDI+中的直线、曲线和图形
使用图形对象进行绘制的方法:
GDI+ 中的 Graphics 类提供了绘制前面列表中的各项的方法:DrawLine、DrawRectangle、DrawEllipse、DrawPolygon、DrawArc、DrawCurve(针对基数样条)和 DrawBezier。 这些方法中的每一种都是重载的,即每种方法都支持几个不同的参数列表。 例如,DrawLine 方法的一个变体接收一个 Pen 对象和四个整数,而 DrawLine 方法的另一个变体接收一个 Pen 对象和两个
Point 对象。
绘制直线、矩形和贝塞尔样条的方法具有多个伴随方法,可在一个调用中绘制若干个项:DrawLines、DrawRectangles 和 DrawBeziers。 DrawCurve 方法也有一个伴随方法 DrawClosedCurve,该伴随方法能够通过连接曲线的终点和起点的方式来闭合曲线。
Graphics 类的所有绘制方法与 Pen 对象共同工作。 若要进行绘制,必须至少创建两个对象:Graphics 对象和 Pen 对象。 Pen 对象存储要绘制项的特性,如线宽和颜色。 将 Pen 对象作为参数之一传递给绘制方法。 例如,下面的示例演示 DrawLine 方法的一个变体接收一个 Pen 对象和四个整数,并绘制一个宽 100、高 50 且左上角位于 (20, 10) 的矩形:
myGraphics.DrawRectangle(myPen, 20, 10, 100, 50);
1. 创建用于绘图的Graphic对象的三种方法:
1). 在窗体或控件的 Paint 事件中接收对图形对象的引用,作为 PaintEventArgs 的一部分。 在为控件创建绘制代码时,通常会使用此方法来获取对图形对象的引用。 同样,您也可以在处理 PrintDocument 的 PrintPage 事件时获取作为 PrintPageEventArgs 的属性的图形对象。
示例:
private void Form1_Paint(object sender,
System.Windows.Forms.PaintEventArgs pe)
{
// Declares the Graphics object and sets it to the Graphics object
// supplied in the PaintEventArgs.
Graphics g = pe.Graphics;
// Insert code to paint the form here.
}
2). 调用某控件或窗体的 CreateGraphics 方法以获取对 Graphics 对象的引用,该对象表示该控件或窗体的绘图图面。 如果想在已存在的窗体或控件上绘图,请使用此方法。
Graphics g;
// Sets g to a graphics object representing the drawing surface of the
// control or form g is a member of.
g = this.CreateGraphics();
3). 由从 Image 继承的任何对象创建 Graphics 对象。 此方法在您需要更改已存在的图像时十分有用。
Bitmap myBitmap = new Bitmap(@"C:\Documents and
Settings\Joe\Pics\myPic.bmp");
Graphics g = Graphics.FromImage(myBitmap);
2. 在Windows窗体上绘制线条:
// 创建画笔
Pen pen = new Pen(Color.FromArgb(255, 0, 0, 0), 1);
// 绘制直线
e.Graphics.DrawLine(pen, 20, 10, 300, 100);
pen.Dispose();
3. 在Windows窗体上绘制形状
System.Drawing.Pen myPen = new System.Drawing.Pen(System.Drawing.Color.Red);
System.Drawing.Graphics formGraphic = this.CreateGraphics();
formGraphic.DrawEllipse(myPen, new Rectangle(0, 0, 200, 300));
formGraphic.DrawRectangle(myPen, new Rectangle(0, 0, 200, 300));
myPen.Dispose();
formGraphic.Dispose();
4. 绘制文本
System.Drawing.Graphics formGraphic = this.CreateGraphics();
string drawString = "GDI+绘制文字演示";
System.Drawing.Font drawFont = new System.Drawing.Font("微软雅黑", 16);
System.Drawing.Brush drawBrush = new System.Drawing.SolidBrush(System.Drawing.Color.Black);
float x = 150.0F;
float y = 50.0F;
System.Drawing.StringFormat drawFormat = new System.Drawing.StringFormat();
formGraphic.DrawString(drawString, drawFont, drawBrush, x,y,drawFormat);
drawFont.Dispose();
drawBrush.Dispose();
formGraphic.Dispose();
5. 创建图像
创建一个 Image 类(如 Bitmap)的新对象,
创建一个 Graphics 对象来引用要使用的绘图图面,
然后调用 Graphics 对象的 DrawImage 方法。 将在图形类所表示的绘图表面上绘制图像。 可以在设计时使用图像编辑器创建和编辑图像文件,而在运行时使用 GDI+ 呈现图像。
public void DrawImage()
{
Bitmap myBitmap = new Bitmap(System.Environment.GetFolderPath(Environment.SpecialFolder.MyPictures) + @"\Lighthouse.jpg");
System.Drawing.Graphics formGraphic = this.CreateGraphics();
formGraphic.DrawImage(myBitmap, 10, 10);
}
6. 绘制椭圆和圆弧
myGraphics.DrawEllipse(myPen, 100, 50, 80, 40);
myGraphics.DrawArc(myPen, 100, 50, 140, 70, 30, 180);
7. GDI+ 中的基数样条
基数样条是一连串单独的曲线,这些曲线连接起来形成一条较大的曲线。 样条由点的数组和张力参数指定。 基数样条平滑地经过数组中的每个点;曲线的陡度上没有尖角和突然的变化。
绘制基数样条的方法:
DrawCurve(Pen,Point[]) 绘制经过一组指定的 Point 结构的基数样条。
DrawCurve(Pen,PointF[]) 绘制经过一组指定的 PointF 结构的基数样条。
DrawCurve(Pen,Point[], Single) 使用指定的张力绘制经过一组指定的 Point 结构的基数样条。
DrawCurve(Pen,PointF[], Single) 使用指定的张力绘制经过一组指定的 PointF 结构的基数样条。
DrawCurve(Pen,PointF[], Int32, Int32) 绘制经过一组指定的 PointF 结构的基数样条。 从相对于数组开始位置的偏移量开始绘制。
DrawCurve(Pen,Point[], Int32, Int32, Single) 使用指定的张力绘制经过一组指定的 Point 结构的基数样条。
DrawCurve(Pen,PointF[], Int32, Int32, Single) 使用指定的张力绘制经过一组指定的 PointF 结构的基数样条。 从相对于数组开始位置的偏移量开始绘制。
默认张力为0.5
8. GDI+中的多边形
绘制多边形:
Point[] myPointArray =
{ new Point(0, 0), new Point(50, 30), new Point(30, 60) };
myGraphics.DrawPolygon(myPen, myPointArray);
9. GDI+中的贝塞尔样条
贝塞尔样条是由四个点指定的曲线:两个端点(p1 和 p2)和两个控制点(c1 和 c2)。 曲线开始于 p1,结束于 p2。 该曲线不经过控制点,但是控制点的作用像磁铁一样,在某些方向上拉拽曲线并影响曲线弯曲的方式。
绘制贝塞尔样条曲线:
myGraphics.DrawBezier(myPen, 0, 0, 40, 20, 80, 150, 100, 10);
10. GDI+中的图形路径
路径是通过组合直线、矩形和简单的曲线而形成的。绘制路径(将连续的直线、矩形,曲线,圆弧等连接)
示例:
myGraphicsPath.AddLine(0, 0, 30, 20);
myGraphicsPath.AddEllipse(20, 20, 20, 40);
myGraphicsPath.AddBezier(30, 60, 70, 60, 50, 30, 100, 10);
myGraphics.DrawPath(myPen, myGraphicsPath);
GraphicsPath.StartFigure 方法:不闭合当前图形即开始一个新图形。后面添加到该路径的所有点都被添加到此新图形中。
11. GDI+ 中的画笔和实心形状
GDI+提供了几种填充闭合形状内部的画笔类:SolidBrush、HatchBrush、TextureBrush、LinearGradientBrush 和 PathGradientBrush。 所有这些类都是从 Brush 类继承的。
(1). SolidBrush 实心画笔
SolidBrush mySolidBrush = new SolidBrush(Color.Red);
myGraphics.FillEllipse(mySolidBrush, 0, 0, 60, 40);
(2). HatchBrush 阴影画笔
用阴影画笔填充图形时,要指定前景色、背景色和阴影样式。 前景色是阴影的颜色。
HatchBrush myHatchBrush = new HatchBrush(HatchStyle.Vertical, Color.Blue, Color.Green);
(3). TextureBrush 纹理画笔
纹理画笔,您就可以用位图中存储的图案来填充图形。
Image myImage = Image.FromFile("MyTexture.bmp");
TextureBrush myTextureBrush = new TextureBrush(myImage);
myGraphics.FillEllipse(myTextureBrush, 0, 0, 100, 50);
(4). LinearGradientBrush 渐变画笔
GDI+ 提供两种渐变画笔:线性和路径。 您可以使用线性渐变画笔来用颜色(在您横向、纵向或斜向移过图形时会逐渐变化的颜色)填充图形。 下面的代码示例演示如何用水平渐变画笔填充一个椭圆,当从椭圆的左边缘向右边缘移动时,画笔颜色会由蓝变为绿。
LinearGradientBrush myLinearGradientBrush = new LinearGradientBrush(
myRectangle,
Color.Blue,
Color.Green,
LinearGradientMode.Horizontal);
myGraphics.FillEllipse(myLinearGradientBrush, myRectangle);
12. GDI+ 中的开放曲线和闭合曲线
闭合的曲线具有内部,因此可以用画笔填充。 GDI+ 中的 Graphics 类提供了以下几种填充闭合形状和曲线的方法:FillRectangle、 FillEllipse、FillPie、FillPolygon、 FillClosedCurve、FillPath 和 FillRegion。 只要调用其中有一个方法,就必须将一个特定的画笔类型(SolidBrush、HatchBrush、TextureBrush、LinearGradientBrush
或 PathGradientBrush)作为参数传递。
下面的示例绘制了一个弧形并填充椭圆内部的相应部分:
myGraphics.FillPie(mySolidBrush, 0, 0, 140, 70, 0, 120);
myGraphics.DrawArc(myPen, 0, 0, 140, 70, 0, 120);
FillClosedCurve 方法与 DrawClosedCurve 方法类似。 这两种方法都通过连接结束点和起始点来自动闭合曲线。 下面的示例绘制了一条经过 (0, 0)、(60, 20) 和 (40, 50) 的曲线。 然后,该曲线通过连接 (40, 50) 至起始点 (0, 0) 自动闭合,并且用一种纯色填充内部
Point[] myPointArray =
{ new Point(0, 0), new Point(60, 20), new Point(40, 50) };
myGraphics.DrawClosedCurve(myPen, myPointArray);
myGraphics.FillClosedCurve(mySolidBrush, myPointArray);
FillPath 方法填充了路径的不同部分的内部。 如果路径的某一部分不构成封闭的曲线或图形,FillPath 方法会在填充该部分之前先自动将其闭合。 下面的示例绘制并填充一个路径,该路径由弧形、基数样条、字符串和扇形组成:
SolidBrush mySolidBrush = new SolidBrush(Color.Aqua);
GraphicsPath myGraphicsPath = new GraphicsPath();
Point[] myPointArray = {
new Point(15, 20),
new Point(20, 40),
new Point(50, 30)};
FontFamily myFontFamily = new FontFamily("Times New Roman");
PointF myPointF = new PointF(50, 20);
StringFormat myStringFormat = new StringFormat();
myGraphicsPath.AddArc(0, 0, 30, 20, -90, 180);
myGraphicsPath.AddCurve(myPointArray);
myGraphicsPath.AddString("a string in a path", myFontFamily,
0, 24, myPointF, myStringFormat);
myGraphicsPath.AddPie(230, 10, 40, 40, 40, 110);
myGraphics.FillPath(mySolidBrush, myGraphicsPath);
myGraphics.DrawPath(myPen, myGraphicsPath);
13. GDI+中的区域
区域是输出设备显示区域的一部分。区域可以是简单的(单个矩形)或复杂的(多边形和闭合曲线的组合)。
区域常用于剪辑和命中检测。 剪辑需要将绘制限制到显示区域的一个特定区域,通常是需要更新的部分。 命中检测需要通过检查来确定按下鼠标按钮时光标是否在屏幕的特定区域中。
您可以从矩形或路径中构造区域。 您也可以通过合并现有的区域来创建复杂区域。
Region 类提供以下区域合并方法:Intersect、Union、Xor、Exclude 和 Complement。
两个区域的交集是同时属于两个区域的所有点的集合。 并集是属于一个或另一个或两个区域的所有点的集合。 区域的补集是不在该区域的所有点的集合。
适用于一对区域的Xor方法可生成一个区域,其中包含属于一个区域或另一个区域但不同时属于两个区域的所有点。 适用于一对区域的 Exclude 方法可生成一个区域,其中包含属于第一个区域而不属于第二个区域的所有点。
若要填充区域,需要有 Graphics 对象、Brush 对象和 Region 对象。 Graphics 对象提供 FillRegion 方法,Brush 对象存储填充的特性,如颜色或图案。
myGraphics.FillRegion(mySolidBrush, myRegion);
14. 在 GDI+ 中限制绘制图面
剪辑需要把绘制限制到一个特定的矩形或区域。
区域可从路径构造,路径可包含字符串的轮廓,因此您可以剪辑空心效果的文字。
若要利用剪辑进行绘制,请创建 Graphics 对象,设置其 Clip 属性,然后调用同一 Graphics 对象的绘制方法:
myGraphics.Clip = myRegion;
myGraphics.DrawLine(myPen, 0, 0, 200, 200);
15. 用直线和曲线抗锯齿
当使用 GDI+ 绘制直线时,需要提供直线的起点和终点,但不必提供有关直线上的各个像素的任何信息。 GDI+ 与显示设备驱动程序软件协同工作,确定要启用哪些像素以便在特定显示设备上显示直线。
一项更为复杂的呈现直线的技术需要使用部分透明的像素和不透明的像素。 像素被设为纯红色或红色与背景色的混合色(取决于它们和直线的接近程度)。 这种呈现方式被称为抗锯齿,它可以生成视觉上更感平滑的直线。
若要使用“抗锯齿”功能绘制直线和曲线,请创建 Graphics 类的实例,并将其 SmoothingMode 属性设置为 AntiAlias 或 HighQuality。 然后调用同一 Graphics 类的某个绘制方法。
myGraphics.SmoothingMode = SmoothingMode.AntiAlias;
myGraphics.DrawLine(myPen, 0, 0, 12, 8);
16. 对文本使用抗锯齿效果
“抗锯齿”是指对绘制的图形和文本的粗糙边缘进行平滑处理以改进它们的外观或可读性。 通过托管 GDI+ 类,既可以呈现高质量的抗锯齿的文本,也可以呈现低质量文本。 通常,呈现的质量越高,所需的处理时间越长。 若要设置文本的质量级别,请将 Graphics 的 TextRenderingHint 属性设置为 TextRenderingHint 枚举元素之一
下面的代码示例以两种不同的质量设置绘制文本:
FontFamily fontFamily = new FontFamily("Times New Roman");
Font font = new Font(
fontFamily,
32,
FontStyle.Regular,
GraphicsUnit.Pixel);
SolidBrush solidBrush = new SolidBrush(Color.FromArgb(255, 0, 0, 255));
string string1 = "SingleBitPerPixel";
string string2 = "AntiAlias";
e.Graphics.TextRenderingHint = TextRenderingHint.SingleBitPerPixel;
e.Graphics.DrawString(string1, font, solidBrush, new PointF(10, 10));
e.Graphics.TextRenderingHint = TextRenderingHint.AntiAlias;
e.Graphics.DrawString(string2, font, solidBrush, new PointF(10, 60));