winfrom窗体中使用动态图:
方法一(简单):用label,然后设置为背景图片方法二:使用GDI+ 来实现 (很粗略的实现,没有帧间隔)
Image image = Image.FromFile("e://temp.gif")
FrameDimension fd = new FrameDimension(image.FrameDimensionsList[0])
int count = image.GetFrameCount(fd)
Graphics g = this.panel1.CreateGraphics()
while (true)
{
for (int i = 0 i < count i++)
{
//g.Clear(Color.White)
image.SelectActiveFrame(fd, i)
g.DrawImage(image, new Point(0, 0))
System.Threading.Thread.Sleep(100)
Application.DoEvents()
}
}
方法三:(推荐)
Bitmap animatedGif = new Bitmap("e://temp2.gif")
Graphics g = this.panel1.CreateGraphics()
// A Gif image's frame delays are contained in a byte array
// in the image's PropertyTagFrameDelay Property Item's
// value property.
// Retrieve the byte array...
int PropertyTagFrameDelay = 0x5100
PropertyItem propItem = animatedGif.GetPropertyItem(PropertyTagFrameDelay)
byte[] bytes = propItem.Value
// Get the frame count for the Gif...
FrameDimension frameDimension = new FrameDimension(animatedGif.FrameDimensionsList[0])
int frameCount = animatedGif.GetFrameCount(FrameDimension.Time)
// Create an array of integers to contain the delays,
// in hundredths of a second, between each frame in the Gif image.
int[] delays = new int[frameCount + 1]
int i = 0
for (i = 0 i <= frameCount - 1 i++)
{
delays[i] = BitConverter.ToInt32(bytes, i * 4)
}
// Play the Gif one time...
while (true)
{
for (i = 0 i <= animatedGif.GetFrameCount(frameDimension) - 1 i++)
{
animatedGif.SelectActiveFrame(frameDimension, i)
g.DrawImage(animatedGif, new Point(0, 0))
Application.DoEvents()
Thread.Sleep(delays[i] * 10)
}
}
方法四: 使用.NET 自带的类:System.Drawing.ImageAnimator
最近在做一个图片查看器,由于使用一般的PctureBox,在性能和缩放控制上都无法满足预期的要求,因此所有组件的呈现均是通过重写控件的OnPaint事件来绘制。在查看gif图片时发现Graphics.DrawImage只呈现第一帧,无法满足预期要求,因此经过摸索寻找到了解决自绘gif的较好办法。
这里介绍一个.net自身携带的类ImageAnimator,这个类类似于控制动画的时间轴,使用ImageAnimator.CanAnimate可以判断一个图片是否为动画,调用ImageAnimator.Animate可以开始播放动画,即每经过一帧的时间触发一次OnFrameChanged委托,我们只要在该委托中将Image的活动帧选至下一帧再迫使界面重绘就可以实现动画效果了。
为了方便以后的使用,我将这些代码整合到了一起,形成一个AnimateImage类,该类提供了CanAnimate、FrameCount、CurrentFrame等属性,以及Play()、Stop()、Reset()等动画常用的方法,代码如下:
using System
using System.Collections.Generic
using System.Text
using System.Drawing
using System.Drawing.Imaging
namespace GifTest
{
/**//// <summary>
/// 表示一类带动画功能的图像。
/// </summary>
public class AnimateImage
{
Image image
FrameDimension frameDimension
/**//// <summary>
/// 动画当前帧发生改变时触发。
/// </summary>
public event EventHandler<EventArgs> OnFrameChanged
/**//// <summary>
/// 实例化一个AnimateImage。
/// </summary>
/// <param name="img">动画图片。</param>
public AnimateImage(Image img)
{
image = img
lock (image)
{
mCanAnimate = ImageAnimator.CanAnimate(image)
if (mCanAnimate)
{
Guid[] guid = image.FrameDimensionsList
mFrameCount = image.GetFrameCount(frameDimension)
}
}
}
bool mCanAnimate
int mFrameCount = 1, mCurrentFrame = 0
/**//// <summary>
/// 图片。
/// </summary>
public Image Image
{
get { return image }
}
/**//// <summary>
/// 是否动画。
/// </summary>
public bool CanAnimate
{
get { return mCanAnimate }
}
/**//// <summary>
/// 总帧数。
/// </summary>
public int FrameCount
{
get { return mFrameCount }
}
/**//// <summary>
/// 播放的当前帧。
/// </summary>
public int CurrentFrame
{
get { return mCurrentFrame }
}
/**//// <summary>
/// 播放这个动画。
/// </summary>
public void Play()
{
if (mCanAnimate)
{
lock (image)
{
ImageAnimator.Animate(image, new EventHandler(FrameChanged))
}
}
}
/**//// <summary>
/// 停止播放。
/// </summary>
public void Stop()
{
if (mCanAnimate)
{
lock (image)
{
ImageAnimator.StopAnimate(image, new EventHandler(FrameChanged))
}
}
}
/**//// <summary>
/// 重置动画,使之停止在第0帧位置上。
/// </summary>
public void Reset()
{
if (mCanAnimate)
{
ImageAnimator.StopAnimate(image, new EventHandler(FrameChanged))
lock (image)
{
image.SelectActiveFrame(frameDimension, 0)
mCurrentFrame = 0
}
}
}
private void FrameChanged(object sender, EventArgs e)
{
mCurrentFrame = mCurrentFrame + 1 >= mFrameCount ? 0 : mCurrentFrame + 1
lock (image)
{
image.SelectActiveFrame(frameDimension, mCurrentFrame)
}
if (OnFrameChanged != null)
{
OnFrameChanged(image, e)
}
}
}
使用如下方法调用:
view plaincopy to clipboardprint?
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(0, 0))
}
}
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()
}
}
}
线程时钟控制按钮依次出现,将按钮设置为隐藏,用时钟控制出现的时间,
可以在出现的时候加上透明度,渐变为100%透明
如果时间控制的合适,是可以做到很流畅的动画的
可以使用多线程 加载,就不会影响窗体中 gif 的播放
背景:
一个内容为gif 的图片框
两个按钮
一个文本域
private string str = "" //全局变量private void Init() //加载方法
{
//耗内存 *** 作
Random r = new Random()
for (int i = 0 i < 99999 i++)
{
str = i + " - " + (i * r.Next(50000)).ToString().Substring(0, 1) + str
}
}
private void button1_Click(object sender, EventArgs e)
{
//建立线程,并传入线程执行的方法
Thread thread = new Thread(new ThreadStart(Init))
thread.Start() //启动线程
//Init()
}
private void button2_Click(object sender, EventArgs e)
{
textBox1.Text = str //读取当前变量
}
点击按钮1,开始后台加载数据,
随时点击按钮2,可以看到全局变量的值,在变化
窗体的gif并没有停止
将按钮1的线程注释掉,直接调用 Init()
窗体的gif停掉,按钮均未响应
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)