C# Winform中绘制动画的方法

最近在做一个图片查看器,由于使用一般的PctureBox,在性能和缩放控制上都无法满足预期的要求,因此所有组件的呈现均是通过重写控件的OnPaint事件来绘制。在查看gif图片时发现Graphics.DrawImage只呈现第一帧,无法满足预期要求,因此经过摸索寻找到了解决自绘gif的较好办法。

这里介绍一个.net自身携带的类ImageAnimator,这个类类似于控制动画的时间轴,使用ImageAnimator.CanAnimate可以判断一个图片是否为动画,调用ImageAnimator.Animate可以开始播放动画,即每经过一帧的时间触发一次OnFrameChanged委托,我们只要在该委托中将Image的活动帧选至下一帧再迫使界面重绘就可以实现动画效果了。

为了方便以后的使用,我将这些代码整合到了一起,形成一个AnimateImage类,该类提供了CanAnimate、FrameCount、CurrentFrame等属性,以及Play()、Stop()、Reset()等动画常用的方法,代码如下

ContractedBlock.gif ExpandedBlockStart.gif Code
  1using System;   
  2using System.Collections.Generic;   
  3using System.Text;   
  4using System.Drawing;   
  5using System.Drawing.Imaging;   
  6  
  7namespace GifTest   
  8ExpandedBlockStart.gifContractedBlock.gif{   
  9ExpandedSubBlockStart.gifContractedSubBlock.gif    /**//// <summary>   
 10    /// 表示一类带动画功能的图像。   
 11    /// </summary>   

 12    public class AnimateImage   
 13ExpandedSubBlockStart.gifContractedSubBlock.gif    {   
 14        Image image;   
 15        FrameDimension frameDimension;   
 16ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>   
 17        /// 动画当前帧发生改变时触发。   
 18        /// </summary>   

 19        public event EventHandler<EventArgs> OnFrameChanged;   
 20  
 21ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>   
 22        /// 实例化一个AnimateImage。   
 23        /// </summary>   
 24        /// <param name="img">动画图片。</param>   

 25        public AnimateImage(Image img)   
 26ExpandedSubBlockStart.gifContractedSubBlock.gif        {   
 27            image = img;   
 28  
 29            lock (image)   
 30ExpandedSubBlockStart.gifContractedSubBlock.gif            {   
 31                mCanAnimate = ImageAnimator.CanAnimate(image);   
 32                if (mCanAnimate)   
 33ExpandedSubBlockStart.gifContractedSubBlock.gif                {   
 34                    Guid[] guid = image.FrameDimensionsList;   
 35                    frameDimension = new FrameDimension(guid[0]);   
 36                    mFrameCount = image.GetFrameCount(frameDimension);   
 37                }
   
 38            }
   
 39        }
   
 40  
 41        bool mCanAnimate;   
 42        int mFrameCount = 1, mCurrentFrame = 0;   
 43  
 44ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>   
 45        /// 图片。   
 46        /// </summary>   

 47        public Image Image   
 48ExpandedSubBlockStart.gifContractedSubBlock.gif        {   
 49ExpandedSubBlockStart.gifContractedSubBlock.gif            get return image; }   
 50        }
   
 51  
 52ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>   
 53        /// 是否动画。   
 54        /// </summary>   

 55        public bool CanAnimate   
 56ExpandedSubBlockStart.gifContractedSubBlock.gif        {   
 57ExpandedSubBlockStart.gifContractedSubBlock.gif            get return mCanAnimate; }   
 58        }
   
 59  
 60ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>   
 61        /// 总帧数。   
 62        /// </summary>   

 63        public int FrameCount   
 64ExpandedSubBlockStart.gifContractedSubBlock.gif        {   
 65ExpandedSubBlockStart.gifContractedSubBlock.gif            get return mFrameCount; }   
 66        }
   
 67  
 68ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>   
 69        /// 播放的当前帧。   
 70        /// </summary>   

 71        public int CurrentFrame   
 72ExpandedSubBlockStart.gifContractedSubBlock.gif        {   
 73ExpandedSubBlockStart.gifContractedSubBlock.gif            get return mCurrentFrame; }   
 74        }
   
 75  
 76ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>   
 77        /// 播放这个动画。   
 78        /// </summary>   

 79        public void Play()   
 80ExpandedSubBlockStart.gifContractedSubBlock.gif        {   
 81            if (mCanAnimate)   
 82ExpandedSubBlockStart.gifContractedSubBlock.gif            {   
 83                lock (image)   
 84ExpandedSubBlockStart.gifContractedSubBlock.gif                {   
 85                    ImageAnimator.Animate(image, new EventHandler(FrameChanged));   
 86                }
   
 87            }
   
 88        }
   
 89  
 90ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>   
 91        /// 停止播放。   
 92        /// </summary>   

 93        public void Stop()   
 94ExpandedSubBlockStart.gifContractedSubBlock.gif        {   
 95            if (mCanAnimate)   
 96ExpandedSubBlockStart.gifContractedSubBlock.gif            {   
 97                lock (image)   
 98ExpandedSubBlockStart.gifContractedSubBlock.gif                {   
 99                    ImageAnimator.StopAnimate(image, new EventHandler(FrameChanged));   
100                }
   
101            }
   
102        }
   
103  
104ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>   
105        /// 重置动画,使之停止在第0帧位置上。   
106        /// </summary>   

107        public void Reset()   
108ExpandedSubBlockStart.gifContractedSubBlock.gif        {   
109            if (mCanAnimate)   
110ExpandedSubBlockStart.gifContractedSubBlock.gif            {   
111                ImageAnimator.StopAnimate(image, new EventHandler(FrameChanged));   
112                lock (image)   
113ExpandedSubBlockStart.gifContractedSubBlock.gif                {   
114                    image.SelectActiveFrame(frameDimension, 0);   
115                    mCurrentFrame = 0;   
116                }
   
117            }
   
118        }
   
119  
120        private void FrameChanged(object sender, EventArgs e)   
121ExpandedSubBlockStart.gifContractedSubBlock.gif        {   
122            mCurrentFrame = mCurrentFrame + 1 >= mFrameCount ? 0 : mCurrentFrame + 1;   
123            lock (image)   
124ExpandedSubBlockStart.gifContractedSubBlock.gif            {   
125                image.SelectActiveFrame(frameDimension, mCurrentFrame);   
126            }
   
127            if (OnFrameChanged != null)   
128ExpandedSubBlockStart.gifContractedSubBlock.gif            {   
129                OnFrameChanged(image, e);   
130            }
   
131        }
   
132    }
   
133}
  
134

使用如下方法调用:

ContractedBlock.gif ExpandedBlockStart.gif Code
using System;   
using System.Collections.Generic;   
using System.ComponentModel;   
using System.Data;   
using System.Drawing;   
using System.Drawing.Imaging;   
using System.Text;   
using System.Windows.Forms;   
  
namespace GifTest   
{   
    
public partial class Form1 : Form   
    {   
        AnimateImage image;   
  
        
public Form1()   
        {   
            InitializeComponent();   
            image 
= new AnimateImage(Image.FromFile(@"C:\Documents and Settings\Administrator\My Documents\My Pictures\未命名.gif"));   
            image.OnFrameChanged 
+= new EventHandler<EventArgs>(image_OnFrameChanged);   
            SetStyle(ControlStyles.OptimizedDoubleBuffer 
| ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint, true);   
        }   
  
        
void image_OnFrameChanged(object sender, EventArgs e)   
        {   
            Invalidate();   
        }   
  
        
private void Form1_Load(object sender, EventArgs e)   
        {   
            image.Play();   
        }   
  
        
private void Form1_Paint(object sender, PaintEventArgs e)   
        {   
            
lock (image.Image)   
            {   
                e.Graphics.DrawImage(image.Image, 
new Point(00));   
            }   
        }   
  
        
private void button1_Click(object sender, EventArgs e)   
        {   
            
if (button1.Text.Equals("Stop"))   
            {   
                image.Stop();   
                button1.Text 
= "Play";   
            }   
            
else  
            {   
                image.Play();   
                button1.Text 
= "Stop";   
            }   
            Invalidate();   
        }   
  
        
private void button2_Click(object sender, EventArgs e)   
        {   
            image.Reset();   
            button1.Text 
= "Play";   
            Invalidate();   
        }   
    }   
}

 

 

有点不完美的地方,在Paint事件中,必须锁定Image,否则很容易出现“对象当前正在其他地方使用。”的异常,因为AnimateImage也在使用这个Image对象。如果你有更好的解决办法,欢迎给我留言~~

转载于:https://www.cnblogs.com/cpw999cn/archive/2009/02/07/1385885.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值