5-3  绘制图形

本节学习目标:
n绘制曲线基本要点
n图形类控件的使用
nSystem.Drawing.Drawing2D

5-3-1 绘制曲线

基本形状的绘制,我们可以从图形类提供的方法中找到解决方案,比如三角形即画三条相互连接的直线,心形则依次画几个半圆形组合,关键问题是找准其中的连接点位置,常见图形都可以通过基本方法调用画出。但是一些数学曲线的处理就较为繁琐,不是标准的形状组成,需要两点一线逐一绘制,这里我们以一些常用曲线及图表为例。

1 案例学习:绘制正弦曲线y=sin(x)

本次实验目标是掌握绘制曲线的基本要领,可以在任意窗体或控件上找到各相关点,计算绘制曲线,以正弦曲线为例,首先应找到坐标原点,然后找到每一个曲线上的对应点的坐标,在两点之间画一条直线,如此反复直到曲线末尾。
u 实验步骤(1):
先定制坐标轴,确定坐标原点,依次画两条直线分别作为X,Y轴。因为窗体的左上角坐标为(00),在代码中使用的坐标定位都是相对的,相对于窗体的左上角位置。为了看得清楚,在窗体的四周留出了一部分边缘,使用绝对像素值,将坐标原点定位在(30,窗体高度-100),按钮的上方。随着窗体大小的变化,横坐标轴根据窗体高度绘制在不同位置。
5-7  坐标轴的绘制
u 实验步骤(2):修改源代码如下所示:
Pen myPen = new Pen(Color.Blue, 3);
Point oo1 = new Point(30, this.ClientSize.Height-100);
Point oo2 = new Point(this.ClientSize.Width - 50, this.ClientSize.Height-100);
g.DrawLine(myPen, oo1, oo2);
Point oo3 = new Point(30, 30);
g.DrawLine(myPen, oo1, oo3);
Font f = new Font("宋体",12,FontStyle.Bold);
g.DrawString("x", f, myPen.Brush, oo2);
g.DrawString("y", f, myPen.Brush, 10,10);
       这里也可以通过坐标平移直接指定坐标原点,然后从原点画出两条直线更为简练。
u 实验步骤(3):
    接着在坐标轴上画出正弦曲线,以坐标轴的原点为起点
5-8  正弦曲线
u 实验步骤(4):
    因为窗体中纵坐标的正方向是垂直向下的,和我们在数学中画坐标轴的方向相反,因此,需对纵坐标的值做一些修改。在上面的代码后面添加:
x1 = x2 = 0;
y1 = 0;y2 = this.ClientSize.Height-100;
for (x2 = 0; x2 < this.ClientSize.Width ; x2++)
{
a = 2 * Math.PI * x2 / (this.ClientSize.Width);
y2 = Math.Sin(a);
y2 = (1 - y2) * (this.ClientSize.Height-100)/2;
g.DrawLine(myPen, x1+30, (float)y1, x2+30, (float)y2);
x1 = x2;
y1 = y2;
}
这里a=2 x/坐标轴宽度,实现坐标轴的放大。因为直接根据y=sinx中的x范围画图,画出的正弦曲线很窄,x取值范围是从0-2 为一个周期,也就是几个像素,因此需将曲线放宽,通过改变横坐标来完成。
问题讨论:绘制曲线时的基本方法
根据曲线的计算公式,确定坐标原点,从原点开始,循环绘制直线,不同点与点间的直线构成了一条曲线。
课外练习
1、  使用 DrawPathDrawCurve方法绘制曲线。
2、 使用ScaleTransform缩放坐标轴。

2 案例学习:按百分比绘制饼图

本次练习的目标是掌握绘制统计图形的基本要领,绘制饼图并按比例填充不同颜色,饼图可以直接使用类库中的方法填充图形,不同在于统计类图形需和数据关联,如何获取数据并按不同数据绘制不同比例的饼图是实现的关键。
u 实验步骤(1):
绘制简单的饼图,各部分比例由界面输入或直接指定,按比例生成饼图,不同部分使用不同颜色填充,多次创建画刷,添加代码:
Rectangle r = new Rectangle(50,50,200,100);
Brush b = new SolidBrush(Color.Blue);
g.FillPie(p.Brush, r, 0, 60);
g.FillPie(b, r, 60, 150);
b = new SolidBrush(Color.Yellow);
g.FillPie(b, r, 210, 150);
5-9 平面饼图
这里绘制的是二维饼图,如果希望画出立体效果,可以使用前面介绍的方法画出圆柱体的效果,立体的部分采用黑色阴影处理即可。
u 实验步骤(2):
从前面的例子看出,画饼图直接使用方法FillPie,饼图的各部分主要由参数3,参数4来确定位置,是饼图各部分的角度的关键参数,如果每一部分不确定,或从其他对象中获取数据来动态生成饼图,可以将饼图绘制改为循环语句实现。同样,每一部分的颜色也可以通过获取数据确定,添加代码:
private void Fill(int[] percent,Color[] percolor)
{
Graphics g = this.CreateGraphics();
Rectangle r = new Rectangle(50, 50, 200, 100);
Brush b;
int beginAngle = 0;
for (int i = 0; i <= percent.GetUpperBound(0); i++)
{
b = new SolidBrush(percolor[i]);
g.FillPie(b, r,beginAngle, percent[i]);
beginAngle += percent[i];
}
g.Dispose();
在这里,我们定义了一个方法,接受的输入参数分别为饼图的划分比例和颜色的设置,方法的参数类型还可根据需要调整。输入的参数既可以从数据库表中的指定列获取,也可通过从文件中的数据获取。在调用时确定将饼图切割为几份。
5-10 随输入数据变化的饼图

5-3-2 图形控件使用

1Picturebox控件

图片框是操作图形图像的基本的控件,主要用以显示保存图形图像信息。主要属性和方法定义如表5-5所示:
属性
说明
Image
设置或获取与该控件显示的图像
SizeMode
指示如何显示图像
方法
说明
 Load
显示图像
5-5 PictureBox控件属性及方法

2 案例学习:在图形框中打开图像并添加文字,保存到文件

本次实验目标是在图像上添加文字或自定义图形,并保存到文件。
5-11  打开图像
u 实验步骤(1):
由图4-11所示,从工具箱之中拖拽PictureBox控件到窗体上,设置SizeMode属性为StretchImage,使图片适应图形框控件大小调整,可以使用OpenFileDialog控件,在代码中添加打开文件操作,从界面选择文件打开,也可以直接指定文件路径,达到图4-4效果。
u 实验步骤(2):
用鼠标双击“在图片中添加文字”按钮,进入.cs文件编辑状态准备进行开发,代码加下所示:
private void 添加文字_Click(object sender, EventArgs e)
{
Graphics g = Graphics.FromImage(pictureBox1.Image);
Font f = new Font("隶书", 80, FontStyle.Italic);
Pen p = new Pen(Color.OrangeRed);
g.DrawString("花开花落", f, p.Brush,0,0);
p.Dispose();
g.Dispose();
}
5-12 在图像上添加文字
问题讨论:
执行完上面的代码,并没有在图像上看到绘制的图形,为什么?
需要对图像刷新。当我们在图像上绘制完成时,没有将绘制的结果同步显示在控件的图像中,这时如果我们保存文件,能够看到文件中的变化,如果我们希望同时在窗体控件中看到变化,以确定是否保存修改。需调用图片框的刷新方法来更新图像对象:PictureBox.Refresh()
u 实验步骤(3):
到这里,我们只是在界面上看到了对于图像所作的修改,再打开文件,还没有将修改保存到文件,最后需调用Image类的Save方法将图片框中修改过的图像对象保存到文件,再次打开文件查看结果。
pictureBox1.Image.Save(filename);

3Bitmap

封装 GDI+ 位图,此位图由图形图像及其属性的像素数据组成。Bitmap 是用于处理由像素数据定义的图像的对象。 如图5-6所示。
属性
说明
Size
获取此图像的以像素为单位的宽度和高度
Width
获取此 Image 的宽度
Height
获取此 Image 的高度
方法
说明
FromFile
从指定的文件创建 Image
FromStream
从指定的数据流创建 Image
GetPixel
获取此 Bitmap 中指定像素的颜色
MakeTransparent
使默认的透明颜色对此 Bitmap 透明。
Save
将此图像以指定的格式保存到指定的流中。
RotateFlip
此方法旋转、翻转或者同时旋转和翻转 Image
5-6  Bitmap类的常用属性及方法