65.9K
CodeProject 正在变化。 阅读更多。
Home

创建基于 Microsoft .NET Compact Framework 的动画控件

2004 年 1 月 20 日

CPOL

5分钟阅读

viewsIcon

96564

downloadIcon

717

了解如何构建一个基于 .NET Compact Framework 的动画控件。

本文由 MSDN 提供。

目录

引言

在最近的一个项目中,其中一个要求是在 Microsoft® .NET Compact Framework Windows® 窗体上显示一个动画 GIF。 .NET Compact Framework 的 1.0 版本不具备显示动画 GIF 文件的能力,也不包含完整 .NET Framework 中的 `ImageAnimator` 辅助类。 `ImageAnimator` 类允许动画化具有基于时间的帧的图像。

尽管可以编写 C# 代码来读取 GIF86a 格式的动画 GIF,但我选择了一种更简单、更直接的方式在我的程序中显示动画。

创建故事板

如果您使用您选择的 GIF 编辑器打开一个动画 GIF,您会看到该文件包含几个连续的图像(**帧**)

图 1. 动画帧

这些图像以压缩格式存储,包含有关尺寸、数量和帧之间延迟时间的信息。显示动画的程序会读取这些信息。

许多 GIF 编辑器允许您将图像帧提取为帧的顺序“故事板”

图 2. 故事板

我将其保存到一个单独的位图文件中,后来将其转换为 GIF 格式,因为它在 .NET Compact Framework 中占用的内存更少。现在我将向您展示如何使用此图像创建基于 .NET Compact Framework 的动画控件。

开始动画

我们将要动画化位图的方式相当简单。它依赖于这样一个事实:当您在 .NET Compact Framework 中使用图像时,您不必显示加载到内存中的整个图像。 `graphics.DrawImage` 方法的一个重载版本接受 `Rectangle` 对象作为参数。这个矩形将是我们的方式,用于框定故事板位图中的每个图像。通过移动帧矩形的位置,我们可以动态地加载位图的不同部分显示在我们的窗体上。

我们在 .NET Compact Framework 项目中添加一个名为 `AnimateCtl` 的新类,并将此类派生自 `System.Windows.Forms.Control`

using System;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Imaging;

public class AnimateCtl : System.Windows.Forms.Control
{
   // Add class implementation here
}

让我们向该类添加一个 `public` `Bitmap` 属性,用于从客户端传递位图。不要忘记声明一个 `private` 位图成员,供类内部使用

private Bitmap bitmap;
public Bitmap Bitmap
{
    get
    {
        return bitmap;
    }
    set
    {
        bitmap = value;
    {
{

我们创建的控件将使用从控件检索到的 `Graphics` 对象的 `DrawImage` 方法来绘制帧

private void Draw(int iframe)
{
    //Calculate the left location of the drawing frame
    int XLocation = iframe * frameWidth;

    Rectangle rect = new Rectangle(XLocation, 0, frameWidth, frameHeight);

    //Draw image
    graphics.DrawImage(bitmap, 0, 0, rect, GraphicsUnit.Pixel);
}

此方法接受需要绘制的当前帧号。然后,我们通过计算其左侧位置来创建绘图矩形。

为了实现控件的循环逻辑,我选择了使用 `System.Windows.Forms.Timer`。

尽管还有许多其他选项可以提供相同的功能,例如 `System.Threading.Timer` 甚至创建单独的线程,但 `System.Windows.Forms.Timer` 的使用被证明是一种更简单、更便捷的方法。让我们在控件的构造函数中添加以下代码

public AnimateCtl()
{
    //Cache the Graphics object
    graphics = this.CreateGraphics();
    //Instantiate the Timer
    fTimer = new System.Windows.Forms.Timer();
    //Hook up to the Timer's Tick event
    fTimer.Tick += new System.EventHandler(this.timer1_Tick);
}

在构造函数中,我们缓存控件实例的 `Graphics` 对象并创建一个新的 `Timer` 实例。并且我们不应忘记将 `Timer` 的 `Tick` 事件挂接起来。我们已准备好插入 `StartAnimation` 方法,该方法将实际启动动画

public void StartAnimation(int frWidth, int DelayInterval, int LoopCount)
{

    frameWidth = frWidth;
    //How many times to loop
    loopCount = LoopCount;
    //Reset loop counter
    loopCounter = 0;
    //Calculate the frameCount
    frameCount = bitmap.Width / frameWidth;
    frameHeight = bitmap.Height;
    //Resize the control
    this.Size(frameWidth, frameHeight);
    //Assign delay interval to the timer
    fTimer.Interval = DelayInterval;
    //Start the timer
    fTimer.Enabled = true;
}

此方法接受一些对动画非常重要的参数:帧宽度、延迟间隔和循环次数。

别忘了循环逻辑

private void timer1_Tick(object sender, System.EventArgs e)
{
    if (loopCount == -1) //loop continuously
    {
        this.DrawFrame();
    }
    else
    {
        if (loopCount == loopCounter) //stop the animation
            fTimer.Enabled = false;   
        else
            this.DrawFrame();
    }
}

private void DrawFrame()
{
    if (currentFrame < frameCount-1)
    {
        //move to the next frame
        currentFrame++;
    }
    else
    {
        //increment the loopCounter
        loopCounter++;
        currentFrame = 0;
    }
    Draw(currentFrame);
}

在上面的代码中,在 `timer1_Tick` 事件中,我们检查 `loopCount`(它跟踪已经绘制了多少次循环),并将其与调用 `StartAnimation` 方法时捕获的 `loopCounter` 进行比较。

电影时间!

我们已经完成了 `AnimateCtl`,可以开始实际测试了。首先,我们需要将带有“故事板”的图像文件添加到您的项目中。我们可以通过将此文件设为嵌入资源,或者只需告诉 Visual Studio .NET 2003 将此文件作为项目的一部分进行复制。在解决方案资源管理器中右键单击项目,然后从弹出菜单中选择“添加现有项…”浏览到图像文件,并确保该文件的 `Build Action` 属性设置为 `Content`。

现在,让我们将以下内容插入到您的 `Form` 的构造函数中

public Form1()
{
    //
    // Required for Windows Form Designer support
    //
    InitializeComponent();

    //Instantiate control
    animCtl = new AnimateCtl();
    //Assign the Bitmap from the image file
    animCtl.Bitmap = new Bitmap(@"\Program Files\AnimateControl\guestbk.gif");
    //Set the location
    animCtl.Location = new Point(50, 50);
    //Add to control to the Form
    this.Controls.Add(animCtl);
}

在上面的代码中,我们将动画控件的 `Bitmap` 属性分配给从我们的图像文件创建的 `Bitmap` 对象。

在设计器中将两个按钮放在您的窗体上,并为它们的点击事件添加代码

private void button1_Click(object sender, System.EventArgs e)
{
    animCtl.StartAnimation(92, 100, 3);
}

private void button2_Click(object sender, System.EventArgs e)
{
    animCtl.StopAnimation();
}

运行项目并点击“开始动画”按钮时,您应该会看到动画

图 3. 最终产品

伪动画 GIF 文件中包含的帧数以及帧之间的延迟时间可能会有所不同。在调用 `StartAnimation` 方法时,您肯定需要根据不同的动画调整 `DelayInterval` 参数。

此代码绝非最终版本。 `AnimateCtl` 没有提供可以集成到动画 GIF 中的所有必需功能。例如,`AnimateCtl` 控件无法处理帧之间不同的延迟时间。例如,您可能希望第一个帧显示的时间比其他帧稍长一些。本文提供的代码是您扩展此控件以满足您需求的良好起点。

请记住,显示高分辨率图形动画可能会给系统资源带来很大负担。请注意您可能在其上运行此代码的某些设备的内存和资源限制。不要忘记彻底测试它,并确保您的应用程序没有占用所有内存或占用所有处理器时间。

结论

尽管 .NET Compact Framework 是完整 .NET Framework 的一个子集,但开发人员仍然有能力创建引人注目的用户界面,从而吸引最终用户。通过利用可用的 GIF 编辑器工具和 .NET Compact Framework 的绘图功能,我们能够在他们的智能设备项目中显示动画。

链接

© . All rights reserved.