15.5.1 F# 中实现的动画形式

来源:互联网 发布:免费双色球缩水软件 编辑:程序博客网 时间:2024/05/21 12:50

15.5.1 F# 中实现的动画形式

 

    在本节中,我们将实现显示动画的窗体。在 F # 中,特别有趣,因为,我们将在 F# Interactive 中使用它,创建与实验动画。在这里,F# 开发的典型风格是非常不同于 C#。在 C# 中,我们会实现窗体,创建动画,编译应用程序,然后运行。在 F# 中,我们会实现窗体,把它装载到 F# Interactive,然后,尝试写一些动画,把它们注入到现有的窗体,来看它们如何工作。

    清单 15.16 显示了实现的 F# 窗体。C# 版本在本质上是相同的,你可以在本书的网站上找到它。我们不会讨论 C# 代码,因为必须编译整个应用程序,以显示动画,但我们会继续显示代码所有的有趣部分(例如,创建一些好的动画), 在 C# 和 F# 中。

 

Listing 15.16 Implementing a form for showing animations (F#)

 

open System.Windows.Forms

type AnimationForm() as this = 
  inherit Form() 
  let emptyAnim = forever(drawing(fun _ –> ())) 
  let mutable startTime = DateTime.UtcNow 
  let mutable anim = emptyAnim

  do 
    this.SetStyle(ControlStyles.AllPaintingInWmPaint ||| 
                            ControlStyles.OptimizedDoubleBuffer, true) 
    let tmr = new Timers.Timer(Interval = 25.0) 
    tmr.Elapsed.Add(fun _ -> this.Invalidate() ) 
    tmr.Start()

  member x.Animation 
    with get() = anim 
    and set(newAnim) = 
      anim <- newAnim 
      startTime <- DateTime.UtcNow

  override x.OnPaint(e) = 
    let w, h = x.ClientSize.Width, x.ClientSize.Height 
    e.Graphics.Clear(Brushes.White) 
    e.Graphics.TranslateTransform(float32(w) / 2.0f), float32(h) / 2.0f)) 
    let elapsed = (DateTime.UtcNow - startTime).TotalSeconds 
    let currentDrawing = anim |> readValue (float32(elapsed)) 
    currentDrawing.Draw(e.Graphics)

 

    这个类型是继承自 .NET 的 Form 类,使用可变值,绑定到存储对象的状态。在构造函数的内部,我们创建一个计时器,每 25 毫秒重绘动画的窗体。

    这个类把动画公开为可变属性,可以读取或设置局部的可变值。在设置函数中,我们还置了动画的开始时间。

    绘图在重写的 OnPaint 方法内实现,它使用 readValue 函数,以获得在给定时间的绘图。

    类声明包含在 F# 中的 OOP 几个高级的方面,我们需要解释。窗体继承自 .NET 的 Form 类,直接把  inherit Form() 构造写在类型声明的后面。类的主体开头是几个普通的 let 绑定。第一个声明一个空的动画:包含绘图的常量行为(用 drawing 基元创建),它不画任何内容,我们把它作为初始动画显示在窗体上。为了用动画做实验,需要在 F# Interactive 中创建一个窗体,使用命令式改变以显示动画。这是在 F# 中使用并互式开发时的常用方式,使用可变状态是完全有效的。

    使用一个名为 Animation 的属性执行这种可变。要创建读/写属性,使用 with 关键字,指定读取函数和设置函数作为两个代码块,使用的语法类似于普通函数声明。在设置函数中,我们设置新动画,并重置了开始时间。

    窗体的声明还包含了 as this 构造,直接跟在隐式构造函数的后面。这样,我们可以在构造函数代码中,使用对这个窗体的引用。我们用它来调用 SetStyle 方法,以避免闪烁(||| 运算符是 F# 按位或运算符,它也可用于处理枚举)。我们在创建计时器时,也使用了 this 引用,强制重绘窗体。

    最有趣的部分是 OnPaint 成员,它重写了 .NET form 默认的 OnPaint 方法,并绘制了动画。它被计时器重复调用,使用 Invalidate 方法,使窗体无效时。当清除窗口后,绘制动画是很容易的。我们使用辅助函数 readValue,是我们早先在用行为进行实验时声明的。该函数使可以我们在动画中,绘制当前时间相应的图像。一旦我们有了绘图,就可调用其 Draw 方法,它在由系统提供的图形对象上绘制。

    这是我们必须写的唯一复杂的代码段,为了开始创建动画。现在,我们可以 F# Interactive 中实例化窗体,并设置它的 Animation 属性,为我们以前创建的简单绘图 (其值我们称为 animDrawing)。此时,应该看到一个圆。从这是一个理论上的支吾,你不会看到任何运动,因为绘图总是相同的。要显示真正的动画,还需要使用更有趣的行为。

原创粉丝点击