让我们动起来
我们所使用的让此位图动起来的方法相当简单。它基于这样一个事实,当您在 .NET Framework 精简版中使用图像时,不必显示载入内存的整个图像。graphics.DrawImage 方法的一个重载方法将 Rectangle 对象作为参数接受。我们就用这个矩形将故事板位图中的每个图像作为帧来处理。通过移动帧矩形的位置,我们可以动态载入要在窗体中显示的位图的不同部分。
我们向 .NET 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 { // 在此添加类的实现 } |
向这个类中添加一个公共的 Bitmap 属性,用于从客户端传递位图。不要忘记为这个位图声明一个私有成员,以便在类中使用:
private Bitmap bitmap; public Bitmap Bitmap { get { return bitmap; } set { bitmap = value; { { |
我们创建的这个控件将使用在其中检索的 Graphics 对象的 DrawImage 方法来绘制这些帧:
|
private void Draw(int iframe) { //计算图形框的左边位置 int XLocation = iframe * frameWidth;
Rectangle rect = new Rectangle(XLocation, 0, frameWidth, frameHeight);
//绘制图像 graphics.DrawImage(bitmap, 0, 0, rect, GraphicsUnit.Pixel); } |
此方法接受需要绘制的当前帧号。然后计算图形框的左边位置以创建矩形。
为了实现该控件的循环逻辑,我选择使用 System.Windows.Forms.Timer。
还有不少其他选项可以提供同样的功能,例如使用 System.Threading.Timer 或是创建一个单独的线程也可以达到相同的目的;但是使用 System.Windows.Forms.Timer 更简单方便。在控件的构造函数中添加以下代码:
public AnimateCtl() { //缓存 Graphics 对象 graphics = this.CreateGraphics(); //实例化 Timer fTimer = new System.Windows.Forms.Timer(); //与 Timer 的 Tick 事件挂钩 fTimer.Tick += new System.EventHandler(this.timer1_Tick); } |
在构造函数中,我们从控件的实例中缓存 Graphics 对象并创建一个新的 Timer 实例,然后将其与 Timer 的 Tick 事件挂钩。现在已经可以插入 StartAnimation 方法,以便实际启动动画:
|
public void StartAnimation(int frWidth, int DelayInterval, int LoopCount) {
frameWidth = frWidth; //循环次数 loopCount = LoopCount; //重置循环计数器 loopCounter = 0; //计算 frameCount frameCount = bitmap.Width / frameWidth; frameHeight = bitmap.Height; //调整控件的大小 this.Size(frameWidth, frameHeight); //向计时器指定延迟间隔 fTimer.Interval = DelayInterval; //启动计时器 fTimer.Enabled = true; } |
此方法接受一些非常重要的动画参数:帧宽度、延迟间隔和循环次数。
另外,不要忘记循环逻辑:
|
private void timer1_Tick(object sender, System.EventArgs e) { if (loopCount == -1) //不停地循环 { this.DrawFrame(); } else { if (loopCount == loopCounter) //停止动画 fTimer.Enabled = false; else this.DrawFrame(); } }
private void DrawFrame() { if (currentFrame < frameCount-1) { //移到下一个帧 currentFrame++; } else { //递增 loopCounter loopCounter++; currentFrame = 0; } Draw(currentFrame); } |
在上面代码的 timer1_Tick 事件中,我们检查 loopCount 以跟踪已绘制的循环次数,并将其与调用 StartAnimation 方法时捕获的 loopCounter 相比较。