桂林老师来信询问数学图形绘制问题。分三种情况说明:
一、利用【工具】中的工具绘制
【工具】中有椭圆、矩形、直线工具,直接使用就行。还有钢笔、铅笔工具(在《WPF和Silverlight教程》中有较详细介绍)。下面的方法均需要编制较多程序。
二、编程绘制静态规则图形
利用Shape基类绘制规则图形
Shape基类派生了六个实用类,可以实例化直接使用的对象,如
Ellipse(椭圆)、Line(直线)、Path(路径)、Polygon(绘制封闭的多边形)、Polyline(绘制首尾连接的直线,可以不封闭)和
Rectangle(矩形),Expression Blend中的图形控件使用了其中的对象。Shape的对象共享以下通用属性:
Stroke:说明绘制形状的轮廓颜色;
StrokeThickness:说明形状轮廓的粗细;
Fill:说明如何绘制形状的内部;
还有一些其它属性,这些属性在Blend的【属性】面板中可以找到,不在这里叙述。这些对象控件的使用也很简单,从【工具】面板选择就行,下面只举例说明如何通过编程应用Shape的对象绘制图形。一般在绘制规则图形时会使用到这些类。
要说明的是图形绘制时的坐标体系:
WPF默认的二维坐标原点是设计屏幕的左上角,X正方向向左,Y正方向向下,单位是1英寸(25.4毫米)的1/96。
图3.23.1列举了几个图形绘制方法,界面的根布局类型改为Canvas,按钮事件代码即是图形的绘制程序。
1. 绘制直线
private void button1_Click(object sender,
System.Windows.RoutedEventArgs e)
{
Line line = new Line();//定义直线对象
line.Stroke = System.Windows.Media.Brushes.Red; //设置线的颜色,红色
line.X1 = 0; //直线起点
line.Y1 =
0;
line.X2 = 150; //直线终点
line.Y2 =
320;
line.StrokeThickness = 5; //直线粗细
this.LayoutRoot.Children.Add(line); //装入界面根布局容器中
}

图3.23.1 Shape类图形绘制
2. 绘制椭圆
private void button2_Click(object sender,
System.Windows.RoutedEventArgs e)
{
Ellipse ellipse = new Ellipse();//定义椭圆对象
//属性设置,填充颜色、边粗细、边颜色、宽、高等
ellipse.Fill=System.Windows.Media.Brushes.Green;
ellipse.StrokeThickness =
4;
ellipse.Stroke =System.Windows.Media.Brushes.Gold; //边,金黄色
ellipse.Width = 80;
ellipse.Height = 200;
//椭圆对象相对于父容器对象Canvas的位置,左边距、上边距
Canvas.SetLeft(ellipse,165);
Canvas.SetTop(ellipse,80);
this.LayoutRoot.Children.Add(ellipse);
}
3. 绘制矩形
private void button3_Click(object sender,
System.Windows.RoutedEventArgs e)
{
Rectangle rectangle = new Rectangle();//矩形对象
//属性设置,填充颜色、边粗细、边颜色、宽、高等
rectangle.Fill=System.Windows.Media.Brushes.Blue;
rectangle.StrokeThickness =
4;
rectangle.Stroke
=System.Windows.Media.Brushes.Pink; //边,粉色
rectangle.Width = 80;
rectangle.Height = 200;
//矩形对象相对于父容器对象Canvas的位置,左边距、上边距
Canvas.SetLeft(rectangle,260);
Canvas.SetTop(rectangle,80);
this.LayoutRoot.Children.Add(rectangle);
}
4. 封闭多边形
封闭多边形Polygon的绘制需要指明多边形的顶点坐标,只要有了这些点集,Polygon自动依次连接每个顶点,并且自动将最后1个顶点和第1个顶点连接,绘制出封闭多边形,Polygon有个属性Points,需要声明设置此属性的点集合。
private void button4_Click(object sender,
System.Windows.RoutedEventArgs e)
{
Polygon polygon = new
Polygon();//定义封闭多边形对象
//属性设置,边颜色、填充颜色、边粗细等
polygon.Stroke = System.Windows.Media.Brushes.Red;
//填充,浅海蓝色
polygon.Fill = System.Windows.Media.Brushes.LightSeaGreen;
polygon.StrokeThickness =
2;
Point Point1 = new Point(360,80); //封闭多边形的多个顶点坐标
Point Point2 = new Point(390,90);
Point Point3 = new Point(435,150);
Point Point4 = new
Point(390,200);
Point Point5 = new
Point(360,300);
//定义点集合对象
PointCollection pointCollection = new
PointCollection();
pointCollection.Add(Point1); //将顶点添加到点集合对象
pointCollection.Add(Point2);
pointCollection.Add(Point3);
pointCollection.Add(Point4);
pointCollection.Add(Point5);
polygon.Points = pointCollection; //设置Polygon属性Points的点集合
this.LayoutRoot.Children.Add(polygon);
}
5. 不封闭形状
不封闭形状Polyline
的绘制和Polygon的绘制类似,需要指明顶点坐标,只要有了这些点集,Polyline自动依次连接每个顶点,但最后1个顶点和第1个顶点不会连接,从而绘制出不封闭形状,Polyline也有个属性Points,需要声明设置此属性的点集合。
private void button5_Click(object sender,
System.Windows.RoutedEventArgs e)
{
Polyline polyline = new Polyline();//定义不封闭形状的对象
//属性设置,边颜色、填充颜色、边粗细等
polyline.Stroke
= System.Windows.Media.Brushes.Red;
//填充色,浅海蓝色
polyline.Fill =
System.Windows.Media.Brushes.LightSeaGreen;
polyline.StrokeThickness = 2;
Point Point1 = new Point(460,80); //不封闭形状的多个顶点坐标
Point Point2 = new
Point(490,90);
Point Point3 = new Point(535,150);
Point Point4
= new Point(490,200);
Point Point5
= new Point(460,300);
//定义点集合对象
PointCollection pointCollection = new
PointCollection();
pointCollection.Add(Point1);
//将顶点添加到点集合对象
pointCollection.Add(Point2);
pointCollection.Add(Point3);
pointCollection.Add(Point4);
pointCollection.Add(Point5);
polyline.Points = pointCollection;//Polyline对象属性Points的点集合
this.LayoutRoot.Children.Add(polyline);
}
三、编程绘制动态随机图形
利用Geometry基类绘制动态图形
Geometry类以及派生类可以描绘基本、复杂二维形状的几何图形,可以剪辑图形绘制到屏幕,可以形成动画。Geometry的派生类大致可以分为三个类别:基本几何图形、复合几何图形和路径图形。当然,Geometry类描绘的图形需要借助其他方法显示。
由于内容较多,这里没有详细介绍Geometry类,只是结合自由落体运动轨迹动态图形绘制介绍有关知识。图3.23.2(Example2.23\Window1.xaml)是动态绘制自由落体运动中高度变化的轨迹示例,希望对其他实时图形的绘制有所启发。
图3.23.2左边有个小球,小球(ellipse)被放置在Canvas控件(canvas1)中,从顶端自由下落,在地面弹跳几次后停止,自由落体动画、缓冲曲线设置均使用编程实现。右边是动态绘制的图形,坐标线是直线控件直接放到【设计面板】实现,动态图形点的采集是在定时器的定时处理程序中实现的。右边黑色背景是Canvas控件(canvas2)。运动轨迹的绘制使用几何线段绘制对象PathFigure,此对象有个特点,只要确定绘制的开始点,就会自动连接后面采集的点形成线段,线段需要复合几何图形PathGeometry对象组合形成曲线图形、并借助于Path对象显示。图3.23.2左下方有两个按钮控件,一个用于“启动”(b1,启动自由落体动画),另一个用于“复位”(b2,小球回到开始位置)。最下方有个文本框TextBlock用于显示小球下落过程中高度的数字值,下面是程序。

图3.23.2 实时图形绘制
1.
初始化程序
int i=1; //动画时间计数
DispatcherTimer timer=new
DispatcherTimer();//定时器
PathFigure pf = new PathFigure();//运动轨迹线段绘制
PathGeometry pg = new
PathGeometry();//组合绘制的线段
Path pa = new
Path();//绘制轨迹曲线的容器,用于显示
DoubleAnimation da=new DoubleAnimation();//小球自由落体运动动画
BounceEase easeBounce=new
BounceEase();//缓动曲线定义
DoubleAnimation rt=new DoubleAnimation();//复位动画
public Window1()
{
this.InitializeComponent();
pa.Stroke=Brushes.LightGreen;//绘制颜色,亮绿色
pa.StrokeThickness=2;//绘制的线宽
Canvas.SetTop(this.ellipse,0);
//设置小球起点
startpoint();//确定绘制的开始点,自定义程序
timer.Interval=TimeSpan.FromMilliseconds(10);//定时10毫秒
timer.Tick+=new System.EventHandler(timer_Tick); //定时事件
da.Completed+=new System.EventHandler(da_Completed);//动画完成事件
}
2.
绘制起点自定义程序
private void startpoint()
{
pf.StartPoint = new Point(0,0);//定义绘制的第一个点
//加入到PathFigure对象中,true表示描绘线段
pf.Segments.Add(new LineSegment(new
Point(0,0),true));
pg.Figures.Add(pf); //组合绘制的线段,只要操作一次
pa.Data=pg;//作为Path对象的数据
this.canvas2.Children.Add(pa);//加入Canvas在屏幕显示
Canvas.SetLeft(pa,0);//设置Path对象左边距从0开始,绘制开始的X坐标
Canvas.SetTop(pa,this.canvas2.Height/2);//绘制开始的Y坐标
}
3. 自由落体动画
private void b1_Click(object sender,
System.Windows.RoutedEventArgs e)
{
easeBounce.EasingMode=EasingMode.EaseOut;//缓动曲线模式
da.EasingFunction=easeBounce;//动画缓动曲线设置
da.Duration=TimeSpan.FromSeconds(5);//动画间隔时间5秒
da.From=0;//从高度0开始,起点
da.To=400;//落地高度400,终点
this.ellipse.RenderTransform=new TranslateTransform();//小球位移变换
timer.Start();//启动定时器
ellipse.BeginAnimation(Canvas.TopProperty,da);//启动动画
}
4. 动画完成
private void da_Completed(object sender,
System.EventArgs e)
{
timer.Stop();
}
5. 定时器定时事件
private void timer_Tick(object sender,
System.EventArgs e)
{
double y=Canvas.GetTop(this.ellipse);//获取当前高度
pf.Segments.Add(new LineSegment(new Point(i,y/2),true));//加入
i++;//计数
this.tb.Text=y.ToString();//显示数字值
}
6. 复位动画程序
private void b2_Click(object sender,
System.Windows.RoutedEventArgs e)
{
rt.Duration=TimeSpan.FromSeconds(1);//动画时间1秒
rt.From=400;//开始点
rt.To=0;//终点
this.ellipse.RenderTransform=new TranslateTransform();
ellipse.BeginAnimation(Canvas.TopProperty,rt);
pf.Segments.Clear();//PathFigure对象清0,所有绘制线段消失
i=1;//重新计数
}
以上的编程对初学者有点困难,其实可以寻找其他可以容易画图的软件生成EXE文件,在WPF中连接就相对简单了。