C#应用程序设计教程(第2版)第05章-WPF图形图像编程_第1页
C#应用程序设计教程(第2版)第05章-WPF图形图像编程_第2页
C#应用程序设计教程(第2版)第05章-WPF图形图像编程_第3页
C#应用程序设计教程(第2版)第05章-WPF图形图像编程_第4页
C#应用程序设计教程(第2版)第05章-WPF图形图像编程_第5页
已阅读5页,还剩148页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第五章WPF图形图像编程能够使用WPF技术编写图形图像程序掌握三类绘制图形的方法掌握画笔、画刷绘图形工具能够进行图形变换能够如何处理图像和剪贴板了解WPF3D图形学习目的主要内容5.1WPF和GDI5.2常用的结构5.3使用Shape派生类5.4使用Drawing派生类5.5使用Visual类派生类5.6Pen类和Brush类5.7图形变换5.8位图效果5.9处理图像5.10图像剪贴板功能5.113D图形5.12DirectX3D和XNA介绍

5.1WPF和GDIWPF和GDI的图形图像编程方法有很大不同。GDI一般采用即时模式显示图形和图像,当窗口图形和图像被破坏后,程序员要自己在OnPaint事件处理函数中恢复被破坏的图形和图像。而WPF采用保留模式显示图像,一般由WPF系统自己恢复被破坏的图形和图像。WPF控件外观一般用矢量图形实现,控件能够记录生成控件矢量图形的方法,当外观需要恢复时自动调用这些方法重现自己外观。这样做的好处是图形外观和显示器分辨率无关,能够自适应不同分辨率显示器。WPF提供了三类显示图形的方法,它们是:System.Windows.Shapes.Shape类派生类:这些类都是控件,设置必要的属性,就可以绘制所需要的图形。这类控件最容易使用,但是由于这些控件支持布局和数据绑定等功能,能够响应较多的事件,使用这些控件将会大大增加应用程序的资源消耗,一般只用来在窗口显示少量的图形。System.Windows.Media.Drawing类派生类:这些类都支持XAML,能够实现Shape类派生类相同的功能。这类控件只支持少量的事件及少量的功能,使用这类控件将能极大减少资源消耗,相对于Shape类派生类要写较多的XAML标记。System.Windows.Media.Visual类派生类:这些类对XAML支持有限,绘制图形方法类似GDI+,一般要编写大量的代码,使用类的方法绘制图形,其占用的资源最少5.2常用的结构5.2.1Point和Size结构点结构System.Windows.Point定义点的位置,点结构有两个成员:X,Y,表示点的x轴和y轴的坐标。其构造函数如下:publicPoint(doublex,doubley)System.Windows.Size结构用属性Width和Height描述对象宽和高。其构造函数如下:publicSize(doublewidth,doubleheight)

5.2.2Rect结构矩形结构System.Windows.Rect,用来描述一个矩形,其常用属性和方法如下:属性X、Y:矩形结构左上角的x、y坐标。只读属性Left、Top:矩形结构左上角的x、y坐标。只读属性Right和Bottom:矩形结构对象右下角的x坐标和y坐标。属性Width、Height和Size:矩形结构对象的宽度和高度。构造函数Rect(Pointlocation,Sizesize):参数1代表矩形结构左上角点结构,参数2是表示代表矩形宽和高的Size结构。构造函数Rect(Doublex,Doubley,Doublewidth,Doubleheight):参数依次为矩形左上角x坐标、y坐标、宽和高。还有其他三个构造函数,请参考帮助系统有关内容。静态方法publicstaticRectIntersect(Rectrect1,Rectrect2):返回Rect结构,是两个参数表示的矩形结构的交集。如果没有交集,则返回空。交集概念见5.4.4节。方法publicvoidIntersect(Rectrect):得到调用该方法的矩形结构对象和参数表示的矩形结构的交集。静态方法publicstaticRectUnion(Rectrect1,Rectrect2):返回Rect结构,是两个参数表示的矩形结构的并集。并集概念见5.4.4节。参数2也可为Point。方法publicboolContains(Point或Rect):判断参数表示的点或矩形结构是否在调用该方法的矩形结构对象中。5.2.3Color结构System.Windows.Media.Color结构用来表示颜色。任何一种颜色可以用透明度(a),蓝色(b),绿色(g),红色(r)合成。Color结构支持两种色彩空间sRGB和scRGB。sRGB用无符号32位数代表一种颜色,红色、绿色、蓝色以及透明度各占一个字节,透明度等于0为完全透明,255为完全不透明,完全不透明红色用16进制数表示为:#ffff0000。scRGB代表的颜色中的红色、绿色、蓝色以及透明度分别用0-1之间的Single类型数表示,透明度等于0.0为完全透明,1.0为完全不透明,红色、绿色、蓝色全为0.0表示黑色,全为1.0表示白色,不透明红色表示为:sc#1.0,1.0,0.0,0.0。其常用属性和方法如下:属性R、G、B和A:分别表示sRGB空间的红色、绿色、蓝色以及透明度。属性scR、scG、scB和scA:分别表示scRGB空间的红色、绿色、蓝色以及透明度。publicstaticColorFromRgb(byter,byteg,byteb):得到不透明sRGB颜色。publicstaticColorFromArgb(bytea,byter,byteg,byteb):sRGB颜色。publicstaticColorFromScRgb(floata,floatr,floatg,floatb):scRGB颜色。publicstaticboolAreClose(Colorcolor1,Colorcolor2):由于scRGB颜色可能无法完全相等,用此函数比较两个scRGB颜色是否近似相等。5.3使用Shape派生类Shape派生类包括画线段控件Line、画矩形控件Rectangle、画圆或椭圆控件Ellipse、画多条线段控件Polyline、画由多条线段组成的闭合图形控件Polygon和画任意曲线控件Path。5.3.1公用属性

Fill:Brush类对象,指定封闭图像的填充颜色。Stroke:Brush类对象,指定线的颜色或封闭图形外轮廓线的颜色。StrokeThickness:指定线的宽度或封闭图形外轮廓线的宽度。GeometryTransform:对图形位置进行变换。5.3.2画线控件Line控件Line用来画线段,属性X1和Y1为线段起点,属性X2和Y2为线段终点。

【例5.1】画一条线段的XAML标记如下,注意实际程序必须添加省略的标记。<Grid><!--Window标记及其一些属性被省略,正式程序必须保留--><LineX1="0"Y1="0"X2="100"Y2="100"Stroke="Black"StrokeThickness="10"/></Grid>5.3.3画矩形控件Rectangle控件Rectangle可用来画各种矩形,属性Width、Height、RadiusX和RadiusY分别是矩形的宽、高、圆角矩形的圆角x轴半径和y轴半径。x轴半径要小于等于Width二分之一,y轴半径要小于等于Height二分之一,当二者都等于二分之一,则图形变为圆或椭圆。【例5.2】画矩形和圆角矩形的XAML标记如下,如果Width=Height,为正方形。<Grid><RectangleWidth="100"Height="50"Fill="Blue"Stroke="Black"StrokeThickness="4"><Rectangle.RenderTransform><RotateTransformCenterX="0"CenterY="0"Angle="-45"/></Rectangle.RenderTransform></Rectangle><RectangleMargin="0,150,0,0"Width="100"Height="50"Fill="Blue"RadiusX="20"RadiusY="20"/></Grid>【例5.3】用代码生成矩形,为Grid控件添加属性Name="grid1",在窗体增加按钮,其事件函数如下,单击按钮,则出现一个黑轮廓线,内部填充天蓝色的正方形。privatevoidbutton1_Click(objectsender,RoutedEventArgse){RectanglemyRect=newRectangle();myRect.Stroke=Brushes.Black;myRect.Fill=Brushes.SkyBlue;myRect.Height=50;myRect.Width=50;RotateTransformrotateTransform1=newRotateTransform(-45);myRect.RenderTransform=rotateTransform1;grid1.Children.Add(myRect);}【例5.4】绘制3个重叠的矩形,演示透明效果。将如下标记放到Grid标记中。请读者仔细分析运行后不同位置为什么会产生相应颜色。<GridWidth="200"Height="200"><RectangleFill="#ff0000ff"Margin="0,0,50,50"/> <!--颜色不透明--><RectangleFill="#80ff0000"Margin="50,0,0,50"/> <!--颜色半透明--><RectangleFill="#8000ff00"Margin="25,50,25,0"/> <!--颜色半透明--></Grid>5.3.4画圆或椭圆控件Ellipse控件Ellipse画椭圆时如果Width=Height,则为圆。【例5.5】本例用键盘4个箭头键推动一个红色圆,可以在窗体的4个方向上移动,当圆到了窗体边界,圆就不能继续移动了。(1)创建WPF项目。放置Ellipse控件到Grid面板,拖动Ellipse控件向左上方移动,一直到只有左方和上方的两根指示距离边界的线(图5.1),修改Ellipse控件的控制边界颜色属性Stroke="Red",控制填充颜色属性Fill="Red"。此时Ellipse控件XAML标记如下:<EllipseMargin="37,22,0,0"Name="ellipse1"Stroke="Red"Fill="Red"HorizontalAlignment="Left"Width="100"Height="100"VerticalAlignment="Top"/>

(2)选中Window1窗体,为其增加KeyDown事件函数如下:privatevoidWindow_KeyDown(objectsender,KeyEventArgse){doublex1=ellipse1.Margin.Left;doublex2=ellipse1.Margin.Top;switch(e.Key){caseKey.Left:if(ellipse1.Margin.Left>0)x1-=1;break;caseKey.Right:if((ellipse1.Margin.Left+100)<this.Width)x1+=1;break;

caseKey.Down:if(ellipse1.Margin.Top+100<this.Height)x2+=1;break;caseKey.Up:if(ellipse1.Margin.Top>0) x2-=1;break;}ellipse1.Margin=newThickness(x1,x2,0,0);}(3)运行,可以用4个箭头键移动红色圆。【例5.6】Windows画图程序用拖动鼠标方法画椭圆或圆,实现的方法是以鼠标左键单击处作为矩形的一个顶点,记为顶点1,该点坐标不改变。拖动鼠标移动到另一位置,以此位置作为矩形另一顶点,记为顶点2,顶点1和顶点2在矩形对角线的两端。绘制由顶点1和顶点2定义的矩形的内切椭圆,以显示要绘制椭圆的位置,这个椭圆的位置随着鼠标的移动而改变。鼠标抬起,以鼠标抬起位置为顶点2,用指定的颜色绘制由顶点1和顶点2定义的矩形的内切椭圆,作为最终图形。具体步骤如下。(1)创建WPF项目。放置Ellipse控件到<grid>面板中,拖动Ellipse控件向左上方移动,一直到只有左方和上方的两根指示距离边界的线。此时Ellipse控件XAML标记见例5.5。(2)为<grid>面板增加名字属性:<GridName="grid1">…</grid>(3)为Window1类增加变量:doublex,y;boolmark=false;(4)在Window1类中增加MakeRectangle方法,参数(x1,y1)是鼠标左键单击处点的位置,作为矩形的一个顶点,(x2,y2)是拖动鼠标移动到另一点的位置,返回一个数组,4个元素按顺序分别是定义所画椭圆或圆矩形的左上角x、y座标,矩形宽和高。方法如下:privatedouble[]MakeRectangle(doublex1,doubley1,doublex2,doubley2){doubletop,left,bottom,right;top=y1<=y2?y1:y2;left=x1<=x2?x1:x2; bottom=y1>y2?y1:y2; right=x1>x2?x1:x2;double[]xs={left,top,right-left,bottom-top};returnxs;}(5)为Window1事件MouseDown、MouseUp、MouseMove增加事件处理函数如下:privatevoidWindow_MouseDown(objectsender,MouseButtonEventArgse){if(e.LeftButton==MouseButtonState.Pressed){ellipse1.Visibility=Visibility.Visible;Pointposition=e.GetPosition(grid1);x=position.X;y=position.Y;ellipse1.Width=1; ellipse1.Height=1;ellipse1.Margin=newThickness(x,y,0,0);mark=true;}}privatevoidWindow_MouseMove(objectsender,MouseEventArgse){if(mark){Pointposition=e.GetPosition(grid1);doublepX=position.X;doublepY=position.Y;double[]xs=MakeRectangle(x,y,pX,pY);ellipse1.Width=xs[2];ellipse1.Height=xs[3];ellipse1.Margin=newThickness(xs[0],xs[1],0,0);}}privatevoidWindow_MouseUp(objectsender,MouseButtonEventArgse){mark=false;}(6)编译运行,在Window1控件中拖动鼠标可以画圆或椭圆。5.3.5控件Polyline和PolygonPolyline类的属性Ponints是点结构数组,将数组元素Ponints[0]和Ponints[1]、Ponints[1]和Ponints[2]、…等点连接为多条线段。Polygon和Polyline类功能类似,但将最后一点和开始点连接为线段,由多条线段组成封闭图形。实际上如设置类Polyline属性IsClose=true,也能完成Polygon类相同功能。XAML标记例子:<PolylinePoints="10,11060,10110,110"Stroke="Black"StrokeThickness="4"/>【例5.7】在Windows画图程序中,可以拖动鼠标画任意曲线。本例实现用拖动鼠标左键在主窗体中画曲线。每条曲线都是由若干很短的线段组成。鼠标左键在按下状态,移动鼠标,每次移动很短距离,画出这段线段,所有这些线段组合起来,形成一条曲线。(1)创建WPF项目。在<grid>面板中增加Polyling控件XAML标记。<GridName="grid1"><PolylineStroke="Black"StrokeThickness="1"Name="polyline1/></Grid>(2)为Window1类增加如下变量:PointCollectionmyPoints=newPointCollection();boolmark=false;(3)为Window1控件增加事件处理函数:privatevoidWindow_MouseDown(objectsender,MouseButtonEventArgse){myPoints.Clear(); Pointp1=e.GetPosition(grid1);myPoints.Add(p1);mark=true;}privatevoidWindow_MouseMove(objectsender,MouseEventArgse){if(mark){Pointp1=e.GetPosition(grid1);myPoints.Add(p1);polyline1.Points=myPoints;}}privatevoidWindow_MouseUp(objectsender,MouseButtonEventArgse){mark=false; }(4)运行,在主窗体中拖动鼠标左键可以画线。5.3.6控件Path使用Path控件可以画任意曲线。【例5.8】使用Path控件例子。在Grid标记中增加如下标记:<PathStroke="Black"StrokeThickness="1"Fill="#CCCCFF"><Path.Data> <GeometryGroupFillRule="EvenOdd"><LineGeometryStartPoint="10,10"EndPoint="50,30"/><EllipseGeometryCenter="40,70"RadiusX="30"RadiusY="30"/><RectangleGeometryRect="30,55,100,30"/></GeometryGroup></Path.Data></Path><PathStroke="Black"StrokeThickness="1"Margin="0,50,0,0"Data="M10,100C100,0200,200300,100"/>属性Data也可采用路径标记语法赋值,上例中第二个Path控件采用路径标记语法生成贝塞尔曲线,依靠XMAL解析器内部类型转换器自动将路径标记转换为Geometry对象。该标记中,逗号前后的两个数值表示一个点,点与点之间用空格分开,字符M或m表示Path起点,L或l表示线段终点(起点是当前点),H或h后的一个数值(不是点)表示x坐标值,表示当前点到这个x坐标的水平线段,V或v后的一个数值表示y坐标值,表示当前点到这个y坐标的垂直线段,C或c表示三次贝塞尔曲线控制点,Q或q表示二次贝塞尔曲线控制点,T或t表示平滑贝塞尔曲线控制点,A或a表示椭圆弧指令,Z或z表示Path终点。5.4使用Drawing派生类5.4.1绘图基本方法GeometryDrawing类用来绘制各种形状图形,其属性Geometry用来描述图形的形状,属性Brush用来指定填充封闭图形的刷子,属性Pen指定绘制轮廓的笔。该类必须放在承载容器才能显示所绘制的图形,承载容器必须是FrameworkElement类的派生类,例如窗口或其它内容控件,常用的用法是GeometryDrawing类对象放到DrawingImage控件中,作为Image控件的数据源。【例5.9】本例绘制椭圆,将如下标记放到Grid标记中。这是Drawing类绘图基本方法。

<Image><Image.Source><DrawingImage><DrawingImage.Drawing><GeometryDrawingBrush="Orange"><GeometryDrawing.Geometry><EllipseGeometryCenter="50,50"RadiusX="45"RadiusY="20"/></GeometryDrawing.Geometry><GeometryDrawing.Pen><PenThickness="5"Brush="Black"/></GeometryDrawing.Pen></GeometryDrawing></DrawingImage.Drawing></DrawingImage></Image.Source></Image>【例5.10】可以使用XAML标记或代码绘制图形。publicWindow1(){InitializeComponent();EllipseGeometryellipse2=newEllipseGeometry();ellipse2.RadiusX=45;ellipse2.RadiusY=20;ellipse2.Center=newPoint(50,50);GeometryDrawingaDrawing=newGeometryDrawing();aDrawing.Geometry=ellipse2;aDrawing.Brush=Brushes.Orange;aDrawing.Pen=newPen(Brushes.Black,10.0);DrawingImagedi=newDrawingImage(aDrawing);Gridgrid=newGrid(); Imageimage=newImage();grid.Children.Add(image);image.Source=di;this.Content=grid;}5.4.2Geometry类【例5.11】本例绘制圆角矩形,将如下XAML标记替换例5.9相应XAML标记。<GeometryDrawing.Geometry><RectangleGeometryRect="0,0,100,50"RadiusX="10"RadiusY="10"/></GeometryDrawing.Geometry>【例5.12】本例绘制一条线段,将如下XAML标记替换例5.9相应XAML标记。<GeometryDrawing.Geometry><LineGeometryStartPoint="10,20"EndPoint="100,130"/></GeometryDrawing.Geometry>【例5.13】本例使用PathGeometry类绘制两条线段,将如下XAML标记替换例5.9相应XAML标记。<GeometryDrawing.Geometry><PathGeometry><PathFigure><LineSegmentPoint="0,100"/><LineSegmentPoint="100,100"/></PathFigure></PathGeometry></GeometryDrawing.Geometry>【例5.14】本例使用多条首尾连接线段类PolyLineSegment属性Points路径标记语法重做上例。用如下XAML标记替换上例两条线段的XAML标记,显示效果相同。<PolyLineSegmentPoints="0,100100,100"/>【例5.15】如果有两组不连接或不是首尾连接的图形,可以放到两个PathFigure标记中。将如下XAML标记替换例5.9相应XAML标记。<GeometryDrawing.Geometry><PathGeometry><PathFigureIsClosed="True"><LineSegmentPoint="0,100"IsSmoothJoin="True"/><LineSegmentPoint="100,100"IsSmoothJoin="True"/></PathFigure>

<PathFigureIsClosed="True"StartPoint="100,0"><LineSegmentPoint="0,100"IsSmoothJoin="True"/><LineSegmentPoint="100,100"IsSmoothJoin="True"/></PathFigure> </PathGeometry><GeometryDrawing.Geometry>5.4.3GeometryGroup类如同时绘制多个RectangleGeometry、EllipseGeometry、LineGeometry或PathGeometry图形,就必须将它们放到标记GeometryGroup中。在标记中,每个图形都可以使用属性Transform分别实现旋转、缩放、扭曲和平移等变换。【例5.16】用如下标记替换例5.9相应标记。<GeometryDrawing.Geometry><GeometryGroup><EllipseGeometryCenter="50,50"RadiusX="45"RadiusY="20"/><EllipseGeometryCenter="50,50"RadiusX="20"RadiusY="45"/></GeometryGroup></GeometryDrawing.Geometry>

5.4.4CombinedGeometry类区域是封闭曲线所围内部平面部分。区域可以是简单的(如单个矩形内部)或复杂的(如多边形或闭合曲线的组合)。图5.6中的左边第1图显示了两个区域相交,一个矩形和一个用曲线画出的封闭图形。可以通过合并现有两个区域来创建复杂区域。两个区域的交集(Intersect)是同时属于两个区域的所有点的集合,并集(Union)是多个区域的所有点的集合,两个区域并集减去这两者的交集,即图5.6中的左数第4图显示的黑色区域,称作异或(Xor)。可从矩形区域除去和另一个区域的交集,如图5.6中右数第1图区域,称作Exclude。【例5.17】用如下XAML标记替换例5.9相应XAML标记,从Geometry1标记内的椭圆除去和Geometry2标记内的椭圆相交部分。<GeometryDrawing.Geometry><CombinedGeometryGeometryCombineMode="Exclude"><CombinedGeometry.Geometry1><EllipseGeometryCenter="50,50"RadiusX="45"RadiusY="20"/></CombinedGeometry.Geometry1><CombinedGeometry.Geometry2><EllipseGeometryCenter="50,50"RadiusX="20"RadiusY="45"/></CombinedGeometry.Geometry2></CombinedGeometry></GeometryDrawing.Geometry>5.5使用Visual类派生类Visual类是一个抽象类,其派生类DrawingVisual是一个轻量绘图类,用于呈现形状、图像或文本,它不提供布局、输入、焦点或事件处理功能,从而能够改善其性能。必须将DrawingVisual对象放到一个派生自FrameworkElement类的宿主容器,例如窗体、Image类对象、Panel类对象等。类DrawingVisual对XAML支持很少,大部分图形要用代码实现。5.5.1绘图基本方法【例5.18】使用DrawingVisual绘制一个椭圆和矩形。其代码如下:publicpartialclassWindow1:Window{privateVisualCollection_children;DrawingVisualdv=newDrawingVisual();publicWindow1(){_children=newVisualCollection(this); InitializeComponent();_children.Add(dv);using(DrawingContextdc=dv.RenderOpen()){Rectrect=newRect(newPoint(100,100),newSize(100,50));

dc.DrawRectangle(Brushes.Blue,(Pen)null,rect);dc.DrawEllipse(Brushes.Red,(Pen)null,newPoint(100,50),100,50);}} protectedoverrideintVisualChildrenCount{get{return_children.Count;}}protectedoverrideVisualGetVisualChild(intindex){if(index<0||index>_children.Count){thrownewArgumentOutOfRangeException();}return_children[index];}}5.5.2DrawingContext类方法【例5.19】本例用DrawDrawing方法绘制使用GeometryDrawing方法生成的图形。用如下语句替换例5.18的Using语句中代码。EllipseGeometryellipse2=newEllipseGeometry(); ellipse2.RadiusX=45; ellipse2.RadiusY=20; ellipse2.Center=newPoint(50,50);GeometryDrawingaDrawing=newGeometryDrawing(); aDrawing.Geometry=ellipse2;aDrawing.Brush=Brushes.Orange; dc.DrawDrawing(aDrawing);【例5.20】本例介绍DrawGeometry方法用法。用如下语句替换例5.18的Using语句中代码。dc.DrawGeometry(Brushes.Red,(Pen)null,Geometry.Parse(@"M0,00,100100,100Z"));5.6Pen类和Brush类5.6.1Pen类Pen类包括如下属性:Thickness和Brush:笔的粗细和笔使用的刷子。DashStyle:默认值为实线,也可为虚线或点划线,其子属性Dashes是一个数组,表示虚线或点划线样式,例如Dashes="a,b"中的a和b是数字,a表示是一个宽为Thickness(笔的粗细),长为(a+1)*Thickness的线,其后为空格,按照此规律重复,重复周期长度为(a+b)*Thickness。因此Dashes="0,1"表示实线。如果Dashes="a1,b1,a2,b2",则(a1,b1)和(a2,b2)意义同前,重复周期长度为(a1+b1+a2+b2)*Thickness。数组可以有多项,但必须为偶数项。【例5.21】为字符增加虚下划线的XAML标记如下,注意省略了一些标记。<TextBlockFontSize="36">带下划线字符

<TextBlock.TextDecorations><TextDecorationLocation="Underline"PenThicknessUnit="FontRecommended"><TextDecoration.Pen><PenThickness="3"Brush="Red"><Pen.DashStyle>

<DashStyleDashes="1,4"/></Pen.DashStyle></Pen>

</TextDecoration.Pen></TextDecoration></TextBlock.TextDecorations></TextBlock>DashCap、EndLineCap和StartLineCap:前两个属性是曲线末端的形状,第3个属性是曲线开始的形状,可以是枚举类型PenLineCap的值:Flat(一个未超出直线上最后一点的线帽,等同于无线帽)、Square(一个高度等于直线粗细、长度等于直线粗细一半的矩形)、Round一个直径等于直线粗细的半圆形)、Triangle(一个底边长度等于直线粗细的等腰直角三角形)。LineJoin:两条线段连接处的形状。可以是枚举类型PenLineJoin的值:Miter(常规角顶点)、Bevel(斜角顶点)、Round(圆角顶点)。【例5.22】本例显示Pen类属性LineJoin、EndLineCap和StartLineCap的具体形状。将如下XAML标记增加到Grid记中,运行效果见图。5.6.2SolidColorBrush画刷又称作单色画刷,使用单一颜色填充封闭区域。一般控件属性Background,Shape类属性Fill,GeometryDrawing类属性Brush是一个画刷,如果令其为单一颜色值,实际上设置该属性为SolidColorBrush单色画刷类对象,例如:<GeometryDrawingBrush=“Orange”/>。单色画刷类SolidColorBrush最常用的属性Color,表示画刷的颜色。【例5.23】使用SolidColorBrush单色画刷例子。将XAML标记放到Grid标记中。<RectangleWidth="75"Height="75"><Rectangle.Fill><SolidColorBrushColor="Red"/> <!--也可为其它画刷--></Rectangle.Fill></Rectangle>又称作颜色线形渐变画刷。其常用属性如下:StartPoint和EndPoint:Point结构对象,颜色将沿着两点连线渐变。GradientStops:GradientStop类对象的集合。GradientStop类表示渐变的位置和颜色。位置是StartPoint和EndPoint两点连线用分数表示的相对值,例如,0.5表示连线中间位置。例如下例中,从连线开始(0.0)到四分之一处(0.25),从黄色渐变到红色,从四分之一处到连线终点,从红色渐变到蓝色。5.6.3LinearGradientBrush画刷【例5.24】本例绘制用颜色线形渐变画刷填充的矩形。将以下标记放到Grid标记中。<RectangleWidth="200"Height="100"><Rectangle.Fill><LinearGradientBrushStartPoint="0,0"EndPoint="1,1"><GradientStopColor="Yellow"Offset="0.0"/><GradientStopColor="Red"Offset="0.25"/><GradientStopColor="Blue"Offset="1.0"/></LinearGradientBrush></Rectangle.Fill></Rectangle>【例5.25】本例用代码实现上例相同功能。RectanglediagonalFillRectangle=newRectangle();diagonalFillRectangle.Width=200;diagonalFillRectangle.Height=100;LinearGradientBrushmyLinearGradientBrush=newLinearGradientBrush();myLinearGradientBrush.StartPoint=newPoint(0,0);myLinearGradientBrush.EndPoint=newPoint(1,1);myLinearGradientBrush.GradientStops.Add(newGradientStop(Colors.Yellow,0.0));myLinearGradientBrush.GradientStops.Add(newGradientStop(Colors.Red,0.25));myLinearGradientBrush.GradientStops.Add(newGradientStop(Colors.Blue,1.0));diagonalFillRectangle.Fill=myLinearGradientBrush;Content=diagonalFillRectangle;5.6.4RadialGradientBrush画刷又称作颜色径向渐变画刷。其常用属性如下:Center、RadiusX和RadiusY:定义一个矩形,颜色沿该矩形的内切椭圆或圆径向渐变。三个属性意义分别是内切椭圆或圆的圆心、水平半径和垂直半径。GradientOrigin:颜色渐变开始的点。GradientStops:意义和LinearGradientBrush同名属性类似。【例5.26】本例绘制用颜色径向渐变画刷填充的矩形。将以下标记放到Grid标记中。<RectangleWidth="200"Height="100"><Rectangle.Fill><RadialGradientBrushGradientOrigin="0.4,0.4"Center="0.5,0.5"RadiusX="0.5"RadiusY="0.5"><RadialGradientBrush.GradientStops><GradientStopColor="Yellow"Offset="0"/><GradientStopColor="Red"Offset="0.25"/><GradientStopColor="Blue"Offset="0.75"/><GradientStopColor="LimeGreen"Offset="1"/></RadialGradientBrush.GradientStops></RadialGradientBrush></Rectangle.Fill></Rectangle>5.6.5ImageBrush画刷【例5.27】本例在窗体中显示一幅图像。Stretch属性参见5.6.6节。<CanvasMargin="12,31"> <Canvas.Background><ImageBrushImageSource="../../p.bmp"Stretch="None"/></Canvas.Background></Canvas>【例5.28】本例用代码在矩形中显示一幅图像。在构造函数中增加如下语句。RectangleexampleRectangle=newRectangle();exampleRectangle.Width=75;exampleRectangle.Height=75;ImageBrushmyBrush=newImageBrush();myBrush.ImageSource=newBitmapImage(newUri(@"..\..\p.bmp",UriKind.Relative));exampleRectangle.Fill=myBrush;Content=exampleRectangle;5.6.6TileBrush类TileBrush类是ImageBrush、DrawingBrush和VisualBrush基类,其常用属性如下:Stretch:该属性是Stretch枚举类型,可以取值为:None、Fill、Uniform、UniformToFill。Viewport和ViewportUnits:默认情况下TileBrush画刷完全填充被填充对象,也可仅填充一部分。Viewport决定填充大小和位置,ViewportUnits决定了Viewport是使用绝对坐标还是相对坐标指定的。TileMode:设置该属性可使画刷以基本图块为基础,形成多个基本图块,按照一定规律排列。该属性为TileMode枚举类型值,可取值为:None、Tile、FlipX、FlipY、FlipXY。【例5.29】本例将在矩形中显示4个基本图块。<RectangleWidth="100"Height="100"><Rectangle.Fill><ImageBrushImageSource="..\..\p.bmp"Viewport="0,0,0.5,0.5"TileMode="Tile"/></Rectangle.Fill></Rectangle>5.6.7DrawingBrush画刷【例5.30】本例在窗体中显示一幅图像。注意基本块为被填充矩形左上角第一行的一黑、一白,第二行的一白、一灰4个小矩形,在X和Y方向各重复4次。<RectangleWidth="200"Height="200"><Rectangle.Fill><DrawingBrushViewport="0,0,0.25,0.25"TileMode="Tile"><DrawingBrush.Drawing><GeometryDrawing><GeometryDrawing.Geometry><GeometryGroup><RectangleGeometryRect="0,0,50,50"/><RectangleGeometryRect="50,50,50,50"/></GeometryGroup></GeometryDrawing.Geometry>

<GeometryDrawing.Brush><LinearGradientBrush><GradientStopOffset="0.0"Color="Black"/><GradientStopOffset="1.0"Color="Gray"/></LinearGradientBrush></GeometryDrawing.Brush></GeometryDrawing></DrawingBrush.Drawing></DrawingBrush></Rectangle.Fill> </Rectangle>5.6.8VisualBrush画刷【例5.31】本例在窗体中显示4个按钮。属性TileMode、Viewport参见5.6.6节。<Window…><!--注意省略一些标记,实际程序必须加上--> <Window.Background><VisualBrushTileMode="FlipXY"Viewport="0,0,0.5,0.5">

<VisualBrush.Visual><Button>OK</Button></VisualBrush.Visual>

</VisualBrush></Window.Background></Window> 5.7图形变换5.7.1Transform派生类Transform类是实现二维变换功能的一些类的基类,其派生类包括RotateTransform(旋转)、ScaleTransform(缩放)、SkewTransform(扭曲)和TranslateTransform(平移)。RotateTransform类:其常用属性包括Angle、CenterX和CenterY,该类使图形围绕点(CenterX,CenterY)旋转指定的Angle角度。参见例5.2。ScaleTransform类:其属性CenterX、CenterY指定缩放操作的中心点,属性ScaleX和ScaleY指定图形放大倍数。【例5.32】本例定义了两个矩形,然后宽和高分别放大2倍,但属性CenterX、CenterY不同,注意两者的不同,图5.14中小矩形为初始位置,具体XAML标记如下:<GridHeight="162"><RectangleHeight="50"Width="50"Fill="LightBlue"Margin="12,45,0,0"HorizontalAlignment="Left"VerticalAlignment="Top"><Rectangle.RenderTransform><ScaleTransformCenterX="0"CenterY="0"ScaleX="2"ScaleY="2"/></Rectangle.RenderTransform></Rectangle>

<RectangleWidth="50"Height="50"Fill="LightGreen"Margin="0,45,54,0"HorizontalAlignment="Right"VerticalAlignment="Top"><Rectangle.RenderTransform><ScaleTransformCenterX="25"CenterY="25"ScaleX="2"ScaleY="2"/></Rectangle.RenderTransform></Rectangle></Grid>SkewTransform类:该类可用于对图像进行扭曲,其属性CenterX和CenterY指定扭曲的中心点,属性AngleX和AngleY指定沿x轴和y轴的扭曲角度。【例5.33】本例将矩形沿X轴扭曲45度,XAML标记如下:<RectangleFill="LightBlue"Margin="100,100,100,100"><Rectangle.RenderTransform><SkewTransformCenterX="0"CenterY="0"AngleX="45"AngleY="0"/></Rectangle.RenderTransform></Rectangle>TranslateTransform类:该类平移图像,属性X和Y是沿X轴和Y轴方向距离。5.7.2TransformGroup类

如果要对一个图形完成多个变换,要将多个变换放到TransformGroup标记中。【例5.34】本例将一个按钮沿Y轴方向放大3倍后,旋转45度,XAML标记如下:<ButtonRenderTransformOrigin="0.5,0.5"Margin="100,100,100,100">Click<Button.RenderTransform><TransformGroup><ScaleTransformScaleY="3"/><RotateTransformAngle="45"/></TransformGroup></Button.RenderTransform></Button>5.7.3Matrix结构可以使用矩阵记录所使用的变换。m×n矩阵是以m行和n列排列的一组数字,例如一个3×3矩阵记如图5.15。两个行、列相同的矩阵可以相加,例如:[a33]+[b33]=[c33],矩阵相加运算的规则是:cij=aij+bij,i和j为常量,即相对应位置的项相加。如果有矩阵[amn]和[bnk],[amn]矩阵的列数等于[bnk]矩阵的行数,两个矩阵可以相乘,记为:[amn]*[bnk]=[cmk],矩阵相乘的运算的规则是:cij=∑(ait*btj),其中,i和j为常量,t为变量,初始值为1,最大值为n。如果将平面中的点视为1×2矩阵,则可通过将该点乘以2×2变换矩阵来变形该点。图5.16图是点(2,1)在X轴按比例3放大,Y轴不变,变换结果如图5.17。图5.18表示点(2,1)旋转了90度。图5.19表示点(2,1)以x轴为对称轴的新点。假定要从点(2,1)开始,将其旋转90度,在x方向将其平移3个单位,在y方向将其平移4个单位。可通过先使用矩阵乘法再使用矩阵加法来完成此操作

图5.15矩阵 图5.16矩阵相乘 图5.17比例放大

图5.18点的旋转

图5.19点的对称变换

图5.20点的复合变换

图5.21用仿射矩阵表示的复合变换 图5.22仿射矩阵

如果用矩阵[211]代表点(2,1),用3×3变换矩阵记录两个变换,可用一个矩阵乘法代替以上的两个矩阵运算,见图5.21。注意运算结果的矩阵[261]代表点(2,6),即点(2,1)映射到了点(2,6)。这个3×3矩阵叫作仿射矩阵,它和前边的两个2×2矩阵的关系如图5.22,其中第三列固定为0、0、1。WPF使用System.Windows.Media.Matrix结构封装表示3行3列仿射矩阵,用来记录图形的复杂变换。Matrix结构用属性M11、M12、M21、M22、OffsetX和OffsetY表示3×3变换矩阵的各个项,其结构构造函数如下:publicMatrix(doublem11,doublem12,doublem21,doublem22,doubleoffsetX,doubleoffsetY)Matrix常用方法和属性如下:静态属性publicstaticMatrixIdentity{get;}:得到单位矩阵。方法Rotate(doubleangle):使矩阵增加相对于原点顺时针旋转angle角度变换。方法RotateAt(doubleangle,doublecenterX,doublecenterY):使矩阵增加相对于点(centerX,centerY)顺时针旋转angle角度变换。方法Scale(doublescaleX,doublescaleY):使矩阵增加在X轴和Y轴方向对图形放大或缩小的变换。参数1指定在X轴方向缩放的值,参数2指定在Y轴方向缩放的值。方法Translate(doubleoffsetX,doubleoffsetY):使矩阵增加在(在)X轴和Y轴方向移动的变换。参数1指定在X轴方向移动的值,参数2指定在Y轴方向移动的值。方法PointTransform(Pointpoint):对point点进行变换,参数也可为点数组5.7.4MatrixTransform类【例5.35】本例说明MatrixTransform.类使用方法,如下XAML标记。<ButtonMinWidth="100"Height="38"Width="100">Click<Button.RenderTransform><MatrixTransformx:Name="myMatrixTransform"><MatrixTransform.Matrix><MatrixOffsetX="10"OffsetY="10"M11="1.5"M12="1"/></MatrixTransform.Matrix></MatrixTransform></Button.RenderTransform></Button>然后在构造函数最后增加如下语句:Matrixm=myMatrixTransform.Matrix;m.Translate(-100,-100);myMatrixTransform.Matrix=m;5.7.5控件的变换所有控件都可以使用Transform派生类完成变换,例5.36是对控件Button进行变换。所有控件都有属性LayoutTransform和RenderTransform,前者是在布局之前对控件进行变换,而后者则是在布局之后对控件进行变换在窗体显示。【例5.36】本例使用LayoutTransform将Button2旋转30度,运行效果见图5.25。如果修改Button.LayoutTransform为Button.RenderTransform,运行效果如图5.26。<Window…Height="175"Width="162"><!--一些标记未给出--><StackPanelWidth="137"Height="140"><ButtonHeight="30"Name="button1"Width="100">Button1</Button><ButtonHeight="30"Name="button2"Width="100">Button2<Button.LayoutTransform><RotateTransformAngle="30"CenterX="50"/></Button.LayoutTransform></Button><ButtonHeight="30"Name="button3"Width="100">Button3</Button></StackPanel></Window>5.7.6Drawing类图形变换Geometry派生类RectangleG

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论