关闭

WinForm中正确显示GIF动画

标签: winform
229人阅读 评论(0) 收藏 举报
分类:

1.摘抄

从网上查到了一些WinForm中显示GIF动画的方法,其中有一些懒人方法,不管是PictureBox控件、Label控件还是什么的,直接将动画图像丢给它们的Image,又或者添加到资源,你会发现动画要么不动,要么被窗体遮挡后窗体的重画会使动画失效(在Vista系统中百试百灵)。正确显示动画并不是什么难题,只是懒人采用了错误的方法。

System.Drawing命名空间中为我们提供了处理这些包含时间帧的动画图像的密封类ImageAnimator。查看MSDN文档中《ImageAnimator.Animate 方法》的文章时会看到一个不错的范例。我把它摘出来,演示利用ImageAnimator与直接引用资源两种方法的不同。

WinForm中正确显示GIF动画 - qiulei_21 - 见证我心

using System;    
using System.Drawing;    
using System.Reflection;    
using System.Windows.Forms;    
   
public class animateImage : Form    
{    
    //动画图像(来自嵌入资源)    
     Image animatedImage = Image.FromStream(    
         Assembly.GetAssembly(typeof(animateImage))    
         .GetManifestResourceStream("ImageAnimatorExample.Animation.gif"));    
    //是否正在显示动画    
    bool currentlyAnimating = false;    
   
    //开始动画    
    public void AnimateImage()    
     {    
        if (!currentlyAnimating)    
         {    
             ImageAnimator.Animate(animatedImage, new EventHandler(this.OnFrameChanged));    
             currentlyAnimating = true;    
         }    
     }    
   
    //动画帧发生更改触发的事件处理代码    
    private void OnFrameChanged(object o, EventArgs e)    
     {    
        //重绘窗体    
        this.Invalidate();    
        //Controls[0].Invalidate(); //让窗体上的Label控件重绘    
     }    
   
    protected override void OnPaint(PaintEventArgs e)    
     {    
        //开始动画    
         AnimateImage();    
        //得到动画的下一帧准备渲染    
         ImageAnimator.UpdateFrames();    
        //将这帧画到窗体上    
         e.Graphics.DrawImage(this.animatedImage, new Point(0, 40));    
        //为了区分与Label控件而显示的文字    
         e.Graphics.DrawString("ImageAnimator+OnPaint", Font, SystemBrushes.ControlText, new PointF(0, 40));    
     }    
   
    protected override void OnLoad(EventArgs e)    
     {    
        //加载一个Label控件,为了区别与ImageAnimator方式显示动画的不同    
        new Label()    
         {    
             AutoSize = false,    
             Image = animatedImage,    
             Parent = this,    
             Location = new Point(0, 10),    
             Size = animatedImage.Size,    
             Text = "Label"   
         };    
   
         Text = "ImageAnimator显示动画图像   F1-博客";    
        //DoubleBuffered = true; //可以开启窗体的双缓冲减少闪烁    
        base.OnLoad(e);    
     }    
   
    protected override bool ProcessCmdKey(ref Message msg, Keys keyData)    
     {    
        if (keyData.Equals(Keys.F1))    
         {    
             System.Diagnostics.Process.Start(    
                "http://hi.baidu.com/wingingbob/blog/item/97fba0039185527e3912bb1b.html");    
         }    
        return base.ProcessCmdKey(ref msg, keyData);    
     }    
   
    //入口点    
    public static void Main()    
     {    
         Application.Run(new animateImage());    
     }    
}   

以上的代码大部分来自MSDN,在测试的时候,试着想办法使窗口重绘(比如被其它窗口遮挡)。我在Vista系统下测试,可以较明显的区分出两个动画的不同

2.我自己的处理:

public partial class gifFrm : Form
    {
        private Image m_img = null;//首先定义私有变量
        private EventHandler evtHandler = null;
        public gifFrm()
        {
            InitializeComponent();
        }

//重载当前winform的OnPaint方法,当界面被重绘时去显示当前gif显示的某一帧
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            if (m_img != null)
            {

         //获得当前gif动画下一步要渲染的帧。
                UpdateImage();

 //将获得的当前gif动画需要渲染的帧显示在界面上的某个位置。
                e.Graphics.DrawImage(m_img, new Rectangle(145, 140, m_img.Width, m_img.Height));
            }
        }

//实现Load方法

        private void gifFrm_Load(object sender, EventArgs e)
        {
            evtHandler = new EventHandler(OnImageAnimate);//为委托关联一个处理方法
            string fileName = Application.StartupPath + "\\dsds.gif";//获取要加载的gif动画文件
            if (System.IO.File.Exists(fileName) == true)
            {
                m_img = Image.FromFile(fileName);

                BeginAnimate();//调用开始动画方法
            }
        }
        private void BeginAnimate()//开始动画方法
        {
            if (m_img != null)
            {
                //当gif动画每隔一定时间后,都会变换一帧那么就会触发一事件,该方法就是将当前image每变换一帧时,都会调用当前这个委托所关联的方法。
                ImageAnimator.Animate(m_img, evtHandler);
            }
        }
        private void OnImageAnimate(Object sender, EventArgs e)//委托所关联的方法
        {
            this.Invalidate();//该方法中,只是使得当前这个winform重绘,然后去调用该winform的OnPaint()方法进行重绘)
        }
        private void UpdateImage()
        {//获得当前gif动画的下一步需要渲染的帧,当下一步任何对当前gif动画的操作都是对该帧进行操作
            ImageAnimator.UpdateFrames(m_img);
        }
        private void StopAnimate()        
        {//关闭显示动画,该方法可以在winform关闭时,或者某个按钮的触发事件中进行调用,以停止渲染当前gif动画。
            m_img = null;
            ImageAnimator.StopAnimate(m_img, evtHandler);
        }

//关闭动画

private void gifFrm_FormClosing(object sender, FormClosingEventArgs e)
        {
            StopAnimate();
        }
    }

(后续实现:终于可以看到gif动画了,如果动画左侧或者上沿再标上一段文字"loading....",这不是和web2,0的效果一样的了么,但是实现起来却复杂的许多。。。)

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:20920次
    • 积分:319
    • 等级:
    • 排名:千里之外
    • 原创:6篇
    • 转载:41篇
    • 译文:0篇
    • 评论:1条
    最新评论