1.摘抄
從網上查到了一些WinForm中顯示GIF動畫的方法,其中有一些懶人方法,不管是PictureBox控件、Label控件還是什麼的,直接將動畫圖像丟給它們的Image,又或者添加到資源,你會發現動畫要麼不動,要麼被窗體遮擋後窗體的重畫會使動畫失效(在Vista系統中百試百靈)。正確顯示動畫並不是什麼難題,只是懶人採用了錯誤的方法。
System.Drawing命名空間中爲我們提供了處理這些包含時間幀的動畫圖像的密封類ImageAnimator。查看MSDN文檔中《ImageAnimator.Animate 方法》的文章時會看到一個不錯的範例。我把它摘出來,演示利用ImageAnimator與直接引用資源兩種方法的不同。
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的效果一樣的了麼,但是實現起來卻複雜的許多。。。)