Silverlight数学引擎(12)——样式编辑器
顺便透露一下,我的一个目的就是做一个几何作图的过关游戏,根据过关的等级显示不同的技能,比如初始技能只有【笔】、【尺】、【规】,当你过了用这些初始竟能画平行线这一关,就会多一个技能【平行线】,所以以后就可以更方便地去画平行线了,嘿嘿,是不是挺有趣!
如果只讲理论,前面介绍的那些基本已经足够了,但是要做成一个有趣的可玩的游戏,那还是相当低路漫漫其修远啊…,首先要考虑的就是清晰、整洁、美观。所以这一节我们就来实现一个样式编辑器,给我们画的图形化化妆,肉可不吃,色不可戒,哈哈。
总结一下我们画的图形,都有哪些视觉上的属性需要考虑呢:
- 线条颜色。
- 填充颜色。
- 线条粗细。
- 线条虚实。
- 透明度。
巧的是,我们目前的图形只有Ellipse和Line,且都是Shape的基类,Shape已经具备了这几个属性,因此我们就可以很方便的实现一个综合这几个属性的样式编辑器。
颜色控件可以直接直接用颜色板控件,但由于其中颜色都是RGB数值表示的,不直观,而我们作图又不需要那么多颜色,就选几种常用的,放在下拉框里选择就可以了,把它叫做BrushPicker控件吧。
在做.net的WinForm或者aspx界面的时候,我们可以很方便地用Color来给控件置色,如下图所示:

但是在Silverlight中时不行的,颜色需要由颜色刷(Brush)来设置,Brush是抽象类,其继承者分为单色画刷和多色画刷,例如我们每次使用单色画刷就要这样去定义:
SolidColorBrush Red = new SolidColorBrush(Colors.Red);
与传统的Color.Red这样的用法相比,这样写就比较麻烦了,特别是用得多的时候,因此我们可以写一个静态类,以达到类似Color.Red这样的使用方式,类定义如下:
public static class Brushes { #region Brush-单色 public static SolidColorBrush FromRGB(byte r, byte g, byte b) { return new SolidColorBrush(Color.FromArgb(255, r, g, b)); } public static SolidColorBrush Any//随机取颜色 { get { return new SolidColorBrush(Color.FromArgb(255, (byte)MathUtils.GetRandValue(0, 255), (byte)MathUtils.GetRandValue(0, 255), (byte)MathUtils.GetRandValue(0, 255))); } } public static readonly SolidColorBrush Transparent = new SolidColorBrush(Colors.Transparent); public static readonly SolidColorBrush Blue = new SolidColorBrush(Colors.Blue); public static readonly SolidColorBrush Gray = new SolidColorBrush(Colors.Gray); public static readonly SolidColorBrush White = new SolidColorBrush(Colors.White); public static readonly SolidColorBrush Black = new SolidColorBrush(Colors.Black); //… #endregion Brush-单色 #region Brush-彩色 public struct LinearGradient { public static LinearGradientBrush YellowGreenH//水平渐变 { get { return FromPara(Colors.Yellow, Colors.Green, true); } } public static LinearGradientBrush YellowGreenV//垂直渐变 { get { return FromPara(Colors.Yellow, Colors.Green, false); } } public static LinearGradientBrush FromPara(Color from, Color to, bool isHorizontal) {//… } } #endregion Brush-彩色 }
BrushPicker控件的实现也很简单,由于是下拉框,我们可以直接集成自ComboBox,然后从Brushes中选取一些画刷,创建一些以这些画刷为填充色的小方块到List中,用户选择到了那个小方块,就用哪个小方块的颜色,当然需要添加一些适当的事件处理。
有了BrushPicker我们的线条颜色和填充颜色的控件就实现了,接下里是线条粗细和透明度还有线条虚实。由于线条粗细和透明度都是double类型的数值,我们就用现成的Slider控件吧,线条虚实比较复杂,是一个double类型的数组,从简单易用的角度出发,我们就选用一个固定的数组,这样就可以用一个CheckBox来设置线条虚实了:
{ cbDotted = new CheckBox {Content = "虚线"}; cbDotted.Checked += (s, e) => { if (shape != null) shape.StrokeDashArray = new DoubleCollection { 3 }; }; cbDotted.Unchecked += (s, e) => { if (shape != null) shape.StrokeDashArray = new DoubleCollection(); }; containor0.Children.Add(cbDotted); }
OK,我们的属性编辑器其实就是把这几个控件放在一起组成一个新的控件,这个是非常容易实现的,直接继承StackPanel就行了:
public class ShapeStyleEditor : StackPanel{}
实现了编辑器,那怎么使用呢,我们在CoordinateBase类中定义了Shape,就是我们的图形,现在只要把它放开到接口中与编辑器关联就可以了,其在编辑器中的使用是这样的:
- 首先,当Shape附加到编辑器的时候,编辑器上的各个控件的属性需要跟着变化:
private Shape shape; public Shape Shape { set { if (value == null) this.Visibility = Visibility.Collapsed; else { shape = null;//防止赋值过程中触发事件 this.Visibility = Visibility.Visible; StrokePicker.SeletedBrush = value.Stroke as SolidColorBrush; FillPicker.SeletedBrush = value.Fill as SolidColorBrush; cbDotted.IsChecked = value.StrokeDashArray == null; sliderStrokeThickness.Value = value.StrokeThickness; sliderOpacity.Value = value.Opacity; shape = value; } } }
- 当控件的值发生变化时,将其应用到关联的Shape:
{ sliderOpacity = new Slider {Minimum = 0.1, Maximum = 1.0, Width = 60, Value = 1.0}; sliderOpacity.ValueChanged += (s, e) => { if (shape != null) shape.Opacity = sliderOpacity.Value; }; containor0.Children.Add(sliderOpacity); ToolTipService.SetToolTip(sliderOpacity, "透明度"); }
- 最后我们静态化一个编辑器的实例,改写下我们Drag行为,当选择到某个Shape的时候,将其与编辑器关联。
public override void MouseDown(object sender, MouseButtonEventArgs e) { var item = CS.HitTests(e.ToLogicalPoint(CS)).OrderByDescending(s => s.ZIndex).FirstOrDefault(); if (item != null) { CS.SeletedItem = item; Setting.StyleEditor.Shape = item.Shape; } }
好了,一切就绪,看看效果吧:

样式编辑器顺利实现,但是在使用的过程中我们发现了新的问题,例如变成透明后图形看不见了,选中的图形跟未选中的图形看不出差别,等等等等这些都是致命的问题哟,下节我们就来完善一下界面互动性,例如给被选中的图形增加亮框,增加右键菜单操作等!
浙公网安备 33010602011771号