形状,画刷和变换
概述:
在许多用户界面技术中,普通控件和自定义绘图之间具有清晰的区别。通常来说,绘图特性只用于特定的应用程序--如游戏,数据可视化和物理仿真等。而WPF具有一个非常不同的原则。它以相同的方式处理控件和绘制的图形。
一.理解形状。
在WPF用户界面中,绘制2D图形内容的最简单方法是使用形状(shape) :专门用于表示简单的直线,椭圆,矩形以及多边形的类。从技术角度讲,形状就是所谓的绘图图元。可以组合这些基本元素来创建更复杂的图形。形状最重要的细节是,它们都继承自FrameworkElement类。因此,形状是元素。这样会带来许多重要的结果:
1.形状绘制自身。不需要管理无效的情况和绘图过程。如:当移动内容,改变窗口尺寸或改变形状属性时,不需要手动重新绘制形状。
2.使用与其他元素相同的方式组织形状。换句话说,可在学过的任何布局容器中放置一个形状(尽管,Canvas明显是最有用的容器,因为它允许在特定的坐标位置放置形状,当构建复杂的具有多个部分的图画时,这是很重要的)。
3.形状支持与其他元素相同的事件。这意味着为了处理焦点,按下键盘,移动鼠标以及单击鼠标等,不需要进行任何额外的工作。可以使用用于其他元素的相同的事件集,并且同样支持工具提示,上下文菜单和拖放操作。
二.Shape 类
每个形状都继承自抽象的System.Windows.Shapes.Shape类。如下显示了形状类的继承层次。
如图 ,只有很少一部分类继承自Shape类。Line(直线),ellipse(椭圆),Rectangle(长方形,矩形),Polyline是一系列相互连接的直线,Polygon是由一系列相互连接的直线形成的闭合图形,最后Path类具有非常强大的功能,能够将多个基本形状组合成一个单独的元素。
<Window xmlns:my="clr-namespace:StudyWPF" x:Class="StudyWPF.形状画刷"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="形状画刷" Height="300" Width="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0">
<Line Stroke="Blue" X1="0" Y1="0" X2="300" Y2="50"></Line>
</StackPanel>
<Canvas Grid.Row="1">
<Ellipse Fill="Tomato" Stroke="Blue" Height="50" Width="100" Margin="5" HorizontalAlignment="Left"></Ellipse>
<Rectangle Fill="Bisque" Stroke="Red" Height="50" RadiusX="20" RadiusY="20" Width="100" Margin="5" HorizontalAlignment="Left"></Rectangle>
<Ellipse Fill="RoyalBlue" Stroke="Blue" Canvas.Left="100" Canvas.Top="50" Width="100" Height="50"></Ellipse>
<Rectangle Fill="DeepSkyBlue" Stroke="Blue" Canvas.Left="30" Canvas.Top="40" Width="100" Height="50"></Rectangle>
</Canvas>
</Grid>
</Window>
Ellipse类没有增加任何属性。Rectangle类只增加了两个属性:RadiusX和RadiusY。如果将这两个属性的值设置成非零,就可以创建出优美的圆形拐角
三。形状的布局:
1. 形状位置 设置:通常不希望使用StackPanel,DockPanle以及WrapPanel面板,因为它们被设计为独立的元素,Grid面板更灵活一些,因为它允许在同一个单元格中放置任意多个元素(尽管不能在单元格中的不同部分定位矩形和椭圆)所以最理想的容器是Canvas,该容器要求使用Left,Top,Right或Bottom附加属性,为每个形状指定坐标。这样可以完全控制形状如何相互重叠;如果使用Canvas容器,标签的顺序是很重要的,在上面的示例中,矩形叠加在椭圆的上面,因为在标签列表中首先出现的是椭圆,所以首先绘制椭圆。
并且:Canvas 容器不需要占据整个窗口。例如,完全可以创建一个Grid面板,并在Grid面板的一个单元格中使用Canvas容器。对于在一个动态的,可以*流动的用户界面中锁定一小部分绘图逻辑,这是一种非常好的方法。
2.使用viewBox控件缩放形状:
使用Canvas控件的唯一限制是图形不能改变自身的尺寸以适应更大或更小的窗口。对于按键这非常合理(在这些情况下,按钮不改变尺寸),但是对于其他类型的图形内容,情况就不同了。例如,可能创建一个希望可以改变大小的复杂图形,从而可以充分利用可用的空间。如果希望联合Canvas控件的精确控制功能和容易改变尺寸功能,可以使用Viewbox元素。用法如下: <Viewbox HorizontalAlignment="Center" Width="45" Height="45" Grid.Row="3" Name="lblProgress" Grid.Column="2" Visibility="Collapsed">
<Canvas RenderTransformOrigin="0.5,0.5"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Width="120" Height="120" >
<Ellipse Width="21.835" Height="21.862"
Canvas.Left="20.1696"
Canvas.Top="9.76358"
Stretch="Fill" Fill="Orange"
Opacity="1.0"/>
<Ellipse Width="21.835" Height="21.862"
Canvas.Left="2.86816"
Canvas.Top="29.9581" Stretch="Fill"
Fill="Black" Opacity="0.9"/>
<Ellipse Width="21.835" Height="21.862"
Canvas.Left="5.03758e-006"
Canvas.Top="57.9341" Stretch="Fill"
Fill="Black" Opacity="0.8"/>
<Ellipse Width="21.835" Height="21.862"
Canvas.Left="12.1203"
Canvas.Top="83.3163" Stretch="Fill"
Fill="Black" Opacity="0.7"/>
<Ellipse Width="21.835" Height="21.862"
Canvas.Left="36.5459"
Canvas.Top="98.138" Stretch="Fill"
Fill="Black" Opacity="0.6"/>
<Ellipse Width="21.835" Height="21.862"
Canvas.Left="64.6723"
Canvas.Top="96.8411" Stretch="Fill"
Fill="Black" Opacity="0.5"/>
<Ellipse Width="21.835" Height="21.862"
Canvas.Left="87.6176"
Canvas.Top="81.2783" Stretch="Fill"
Fill="Black" Opacity="0.4"/>
<Ellipse Width="21.835" Height="21.862"
Canvas.Left="98.165"
Canvas.Top="54.414" Stretch="Fill"
Fill="Black" Opacity="0.3"/>
<Ellipse Width="21.835" Height="21.862"
Canvas.Left="92.9838"
Canvas.Top="26.9938" Stretch="Fill"
Fill="Black" Opacity="0.2"/>
<Ellipse Width="21.835" Height="21.862"
Canvas.Left="47.2783"
Canvas.Top="0.5" Stretch="Fill"
Fill="Black" Opacity="0.1"/>
<Canvas.RenderTransform>
<RotateTransform x:Name="SpinnerRotate"
Angle="0" />
</Canvas.RenderTransform>
<Canvas.Triggers>
<EventTrigger RoutedEvent="ContentControl.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName
="SpinnerRotate"
Storyboard.TargetProperty
="(RotateTransform.Angle)"
From="0" To="360"
Duration="0:0:01"
RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Canvas.Triggers>
</Canvas>
</Viewbox>
3 。 直线:Line形状表示连接一个点和另一个点的一条直线。起点和终点由4个属性设置:(X1,Y1) (X2,Y2)
对于直线,Fill属性不起作用,必须设置Stroke属性。在直线中使用的坐标是相对于放置直线的矩形的左上角的坐标(添加直线时会在容器中保留一块矩形空间用于放置直线,)
4 . 拆线:通过Polyline类可以绘制一系列相互连接的直线。只需要使用Points属性提供一系列X和Y坐标。从技术角度讲,Points属性需要一个PointCollection对象,但是在XAML中使用基于简单字符串的语法
<Polyline Stroke="Blue" StrokeThickness="5" Points="10,150 30,140 50,160 70,130 90,170 110,120 130,180 150,110 170,190 190,100 210,240"></Polyline>