5-3 绘制图形
本节学习目标:
n绘制曲线基本要点
n图形类控件的使用
nSystem.Drawing.Drawing2D
5-3-1 绘制曲线
基本形状的绘制,我们可以从图形类提供的方法中找到解决方案,比如三角形即画三条相互连接的直线,心形则依次画几个半圆形组合,关键问题是找准其中的连接点位置,常见图形都可以通过基本方法调用画出。但是一些数学曲线的处理就较为繁琐,不是标准的形状组成,需要两点一线逐一绘制,这里我们以一些常用曲线及图表为例。
1. 案例学习:绘制正弦曲线y=sin(x)
本次实验目标是掌握绘制曲线的基本要领,可以在任意窗体或控件上找到各相关点,计算绘制曲线,以正弦曲线为例,首先应找到坐标原点,然后找到每一个曲线上的对应点的坐标,在两点之间画一条直线,如此反复直到曲线末尾。
u 实验步骤(1):
先定制坐标轴,确定坐标原点,依次画两条直线分别作为X,Y轴。因为窗体的左上角坐标为(0,0),在代码中使用的坐标定位都是相对的,相对于窗体的左上角位置。为了看得清楚,在窗体的四周留出了一部分边缘,使用绝对像素值,将坐标原点定位在(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、 使用 DrawPath或DrawCurve方法绘制曲线。
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 图形控件使用
1.Picturebox控件
图片框是操作图形图像的基本的控件,主要用以显示保存图形图像信息。主要属性和方法定义如表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); |
3.Bitmap类
封装 GDI+ 位图,此位图由图形图像及其属性的像素数据组成。Bitmap 是用于处理由像素数据定义的图像的对象。 如图5-6所示。
属性 |
说明 |
Size |
获取此图像的以像素为单位的宽度和高度 |
Width |
获取此 Image 的宽度 |
Height |
获取此 Image 的高度 |
方法 |
说明 |
FromFile |
从指定的文件创建 Image。 |
FromStream |
从指定的数据流创建 Image。 |
GetPixel |
获取此 Bitmap 中指定像素的颜色 |
MakeTransparent |
使默认的透明颜色对此 Bitmap 透明。 |
Save |
将此图像以指定的格式保存到指定的流中。 |
RotateFlip |
此方法旋转、翻转或者同时旋转和翻转 Image。 |
表5-6 Bitmap类的常用属性及方法