CSharp Tips:在Form中显示动画图片

本文介绍如何使用C#和ImageAnimator类实现GIF动画显示,包括加载图片、启动及停止动画的方法,并提供了一个完整的示例代码。
在Windows Form的程序中有的时候需要显示动画,例如连接网络的动态图标。传统的做法可能是做一组BMP表示不同的状态,然后在Form上添加一个定时器,隔若干毫秒,绘制下一幅图片,如此循环。但是只能是BMP,没法自动支持本身有动画效果的Gif格式的图片。
在DotNET中有一个ImageAnimator类,动画处理包含基于时间的帧的图像,这样的在C#中就不需要加载一组图片了,一个Gif轻松搞定,程序也干净很多。
 
ImageAnimator类
这个类非常简单,主要有几个方法
1)Animator,启动一个多帧的图片,开始动画显示。这里需要制定一个回调函数onFrameChangedHandler,当图片内部间隔时间达到时触发,通常在这个回调函数中刷新界面,显示下一帧图片。特别强调一点,可能ImageAnimator内部用线呈池的定时器检查时间间隔,所以该回调函数触发时,不在程序的主线程中,要注意同步的问题。
2)CanAnimator方法,判断图片是否是动画图片。
3)StopAnimator方法,比较简单,就是停止正在运行的动画。
4)UpdateFrame方法,使该帧在当前正被动画处理的所有图像中前移。新帧在下一次呈现图像时绘制。如(1)所述onFrameChangedHandler不是在主线程中被触发,所以利用这个事件调用UpdateFrame时一定要考虑同步,如果在绘制图片的同时调用UpdateFrame,或者在调用UpdateFrame时绘制图片都会产生资源冲突的异常。所以建议UpdateFrame和绘制图片的动作都在主线程中去执行。
 
一个完整的示例
显示动画图片的思路是,加载图片,然后调用ImageAnimator.Animator方法,同时指定onFrameChangedHandler毁掉函数;onFrameChangedHandler被触发时重绘界面;在窗口绘制时,调用UpdateFrame,然后绘制图片。
代码如下:
using  System;
using  System.Drawing;
using  System.Collections;
using  System.ComponentModel;
using  System.Windows.Forms;
using  System.Data;
using  System.Diagnostics;
 
namespace  Graphics
{
 
/// <summary>
 
/// Summary description for Form1.
 
/// </summary>

 public class Form1 : System.Windows.Forms.Form
 
{
  
/// <summary>
  
/// Required designer variable.
  
/// </summary>

  private System.ComponentModel.Container components = null;
 
  
private Image   m_imgImage = null;
  
private EventHandler m_evthdlAnimator = null;
 
  
public Form1()
  
{
   
//
   
// Required for Windows Form Designer support
   
//
   InitializeComponent();
   
this.SetStyle(ControlStyles.UserPaint,true);
   
this.SetStyle(ControlStyles.DoubleBuffer,true);
   
this.SetStyle(ControlStyles.AllPaintingInWmPaint,true);
 
   
//
   
// TODO: Add any constructor code after InitializeComponent call
   
//
   m_evthdlAnimator = new EventHandler(OnImageAnimate);
   Debug.Assert(m_evthdlAnimator 
!= null);
  }

 
  
/// <summary>
  
/// Clean up any resources being used.
  
/// </summary>

  protected override void Dispose( bool disposing )
  
{
   
if( disposing )
   
{
    
if (components != null
    
{
     components.Dispose();
    }

   }

   
base.Dispose( disposing );
  }

 
  
protected override void OnPaint(PaintEventArgs e)
  
{
   
base.OnPaint (e);
 
   
if (m_imgImage != null)
   
{
    UpdateImage();
    
// 绘制图片的当前帧
    e.Graphics.DrawImage(m_imgImage,new Rectangle(10,10,m_imgImage.Width,m_imgImage.Height));
   }

  }

 
  
protected override void OnLoad(EventArgs e)
  
{
   
base.OnLoad (e);
 
   m_imgImage 
= Image.FromFile("10.gif"); // 加载测试用的Gif图片
   BeginAnimate();
  }

 
 
 
  
Windows Form Designer generated code
 
  
/// <summary>
  
/// The main entry point for the application.
  
/// </summary>

  [STAThread]
  
static void Main() 
  
{
   Application.Run(
new Form1());
  }

 
  
private void Form1_Closed(object sender, System.EventArgs e)
  
{
   
if (m_imgImage != null)
   
{
    StopAnimate();
    m_imgImage 
= null;
   }

  }

 
  
functions of animator image // End of functions of animator image
 
 }

}

最后还有一点注意事项
动画图片的绘制可能会比较频繁,由此造成闪烁,解决办法有两个:
1)不要调用 this.Invalid()重绘整个窗口,而应该调用 this.Invalid(rect)仅绘制显示图形的区域。
2)指定一下窗口风格,启动窗口的双缓存。
   this.SetStyle(ControlStyles.UserPaint,true);
   this.SetStyle(ControlStyles.DoubleBuffer,true);
   this.SetStyle(ControlStyles.AllPaintingInWmPaint,true);
 
 
参考文档
@{ ViewBag.Title = "修改审核信息"; Layout = "~/Views/Shared/_Layout.cshtml"; } <div class="layui-fluid"> <div class="layui-card"> <div class="layui-card-body" style="padding: 15px;"> <form class="layui-form" id="editForm"> <input type="hidden" id="HistoryId" name="HistoryId" /> <div class="layui-form-item"> <label class="layui-form-label">产品名称</label> <div class="layui-input-block"> <input type="text" id="ProductName" name="ProductName" readonly class="layui-input"> </div> </div> <div class="layui-form-item"> <label class="layui-form-label">产品图号</label> <div class="layui-input-block"> <input type="text" id="ProductNo" name="ProductNo" readonly class="layui-input"> </div> </div> <div class="layui-form-item"> <label class="layui-form-label">工艺路线编号</label> <div class="layui-input-block"> <input type="text" id="ProcessNo" name="ProcessNo" readonly class="layui-input"> </div> </div> <div class="layui-form-item"> <label class="layui-form-label">工艺路线版本</label> <div class="layui-input-block"> <input type="text" id="ProcessVersion" name="ProcessVersion" readonly class="layui-input"> </div> </div> <div class="layui-form-item"> <label class="layui-form-label">工程版本</label> <div class="layui-input-block"> <input type="text" id="AllotStepVersion" name="AllotStepVersion" readonly class="layui-input"> </div> </div> <div class="layui-form-item"> <label class="layui-form-label">编制</label> <div class="layui-input-block"> <input type="text" id="Compile" name="Compile" placeholder="请输入编制人" class="layui-input"> </div> </div> <div class="layui-form-item"> <label class="layui-form-label">校核</label> <div class="layui-input-block"> <input type="text" id="Collation" name="Collation" placeholder="请输入校核人" class="layui-input"> </div> </div> <div class="layui-form-item"> <label class="layui-form-label">标准化</label> <div class="layui-input-block"> <input type="text" id="Standardization" name="Standardization" placeholder="请输入标准化人" class="layui-input"> </div> </div> <div class="layui-form-item"> <label class="layui-form-label">批准人</label> <div class="layui-input-block"> <input type="text" id="ApprovedPerson" name="ApprovedPerson" placeholder="请输入批准人" class="layui-input"> </div> </div> <div class="layui-form-item" style="text-align:center; margin-top:30px;"> <button class="layui-btn" lay-submit lay-filter="submitForm">保存</button> <button type="button" class="layui-btn layui-btn-primary" onclick="layer.closeAll()">关闭</button> </div> </form> </div> </div> </div> <script> layui.use(['form', 'layer'], function () { var form = layui.form; var layer = layui.layer; var $ = layui.jquery; //var historyId = getUrlParam('HistoryId'); var historyId = '@Html.Raw(@ViewBag.historyId)'; //加载中。。。。。 loading(); // 获取URL参数 function getUrlParam(name) { var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); var r = window.location.search.substr(1).match(reg); return r != null ? decodeURIComponent(r[2]) : null; } // 加载数据 function loadData() { if (!historyId) { layer.alert('缺少HistoryId'); return; } $.ajax({ url: '../ReviewHistory/FindHistoryById1', type: 'POST', contentType: 'application/json', data: JSON.stringify({ HistoryId: historyId }), success: function (res) { if (res.success) { var data = res.data; $('#HISTORYID').val(data.HISTORYID); $('#PRODUCTNAME').val(data.PRODUCTNAME); $('#PRODUCTNO').val(data.PRODUCTNO); $('#PROCESSNO').val(data.PROCESSNO); $('#PROCESSVERSION').val(data.PROCESSVERSION); $('#ALLOTSTEPVERSION').val(data.ALLOTSTEPVERSION); $('#COMPILE').val(data.COMPILE); $('#COLLATION').val(data.COLLATION); $('#STANDARDIZATION').val(data.STANDARDIZATION); $('#APPROVEDPERSON').val(data.APPROVEDPERSON); $('#REVIEWREMARK').val(data.REVIEWREMARK); } else { layer.alert(res.message || '加载失败'); } }, error: function () { layer.alert('请求失败,请检查网络'); } }); } // 提交表单 form.on('submit(submitForm)', function (data) { $.ajax({ url: '../ReviewHistory/UpdateReviewField', type: 'POST', contentType: 'application/json', data: JSON.stringify(data.field), success: function (res) { if (res.success) { layer.alert('保存成功', function () { parent.layer.closeAll(); // 关闭弹窗 parent.location.reload(); // 刷新父页面 }); } else { layer.alert(res.message || '保存失败'); } }, error: function () { layer.alert('提交失败'); } }); return false; }); // 初始化 loadData(); }); </script> 将这个以下面的结构方式修改 @{ ViewBag.Title = "Edit"; Layout = "~/Views/Shared/_Layout.cshtml"; } @Html.AntiForgeryToken() <style> .layui-form-pane .layui-form-label { width: 150px; } </style> <div class="x-body"> <div class="layui-form layui-form-pane"> <input type="hidden" id="LineId" name="LineId" /> <input type="hidden" id="UsingFlg" name="UsingFlg" /> <input type="hidden" id="UpdDate" name="UpdDate" /> <div class="layui-form-item"> <label class="layui-form-label x-required">产线编号</label> <div class="layui-input-inline" style="width:200px;"> <input type="text" id="LineNo" name="LineNo" data-require="产线编号不能为空" maxlength="30" autocomplete="off" class="layui-input"> </div> <label class="layui-form-label x-required">产线名称</label> <div class="layui-input-inline" style="width:200px;"> <input type="text" id="LineName" name="LineName" data-require="产线名称不能为空" maxlength="50" autocomplete="off" class="layui-input"> </div> </div> <div class="layui-form-item"> <label class="layui-form-label x-required">工厂编号</label> <div class="layui-input-inline" style="width:200px;"> <input type="text" id="FactoryId" name="FactoryId" readonly="readonly" autocomplete="off" class="layui-input rd"> </div> <div class="layui-input-inline" style="width:200px;"> <input type="text" id="FactoryName" name="FactoryName" readonly="readonly" autocomplete="off" class="layui-input rd"> </div> <div class="layui-input-inline" style="width:50px;"> <button class="layui-btn layui-btn-normal" style="padding:0 12px !important;" id="FactoryBtn" name="FactoryBtn" type="button">选择</button> </div> </div> <div class="layui-form-item"> <label class="layui-form-label x-required">返工代码</label> <div class="layui-input-inline" style="width: 560px; "> <input type="text" id="RwkCode" data-require="返工代码不能为空!" maxlength="25" onkeyup="this.value=this.value.replace(/[^a-zA-Z0-9]*$/g,'')" autocomplete="off" class="layui-input"> </div> </div> <div class="layui-form-item"> <label class="layui-form-label">备注</label> <div class="layui-input-inline" style="width: 560px;"> <textarea id="Remark" name="Remark" maxlength="100" placeholder="" class="layui-textarea"></textarea> </div> </div> @*<div class="layui-form-item"> <label class="layui-form-label">周数据链接</label> <div class="layui-input-inline" style="width: 500px;"> <input type="text" id="Week" name="Week" maxlength="50" class="layui-input"> </div> </div> <div class="layui-form-item"> <label class="layui-form-label">月数据链接</label> <div class="layui-input-inline" style="width: 500px;"> <input type="text" id="Month" name="Month" maxlength="50" class="layui-input "> </div> </div>*@ <div class="layui-form-item" style="position: fixed; bottom: 30px; width: 100%;"> <div class="layui-row"> <div class="layui-col-xs3 layui-col-xs-offset5"> <button class="layui-btn" id="btnSubmit">保存</button> <button class="layui-btn" id="btnCancel">关闭</button> </div> </div> </div> </div> </div> <script> layui.use(['tree','table','util','form'], function () { var tree = layui.tree; var layer = layui.layer; var util = layui.util; var table = layui.table; var form = layui.form; var LineId = '@Html.Raw(@ViewBag.LineId)'; //加载中。。。。。 loading(); // 初始化回调 function initCallBack(data) { if (data.success == false) { alertMessage(data.message); closeLoading(); x_admin_close(); return; } if (LineId != "") { $("#LineNo").attr('readonly', 'readonly'); $("#LineNo").addClass("rd"); var dProdLine = JSON.parse(data.data)[0]; $("#LineNo").val(dProdLine.LINE_NO); $("#LineName").val(dProdLine.LINE_NAME); $("#FactoryId").val(dProdLine.FACTORYID); $("#FactoryName").val(dProdLine.FACTORYNAME); $("#RwkCode").val(dProdLine.RWKCODE); $("#Remark").val(dProdLine.REMARK); //$("#Week").val(dProdLine.WEEK); //$("#Month").val(dProdLine.MONTH); $("#LineId").val(dProdLine.LINE_ID); $("#UsingFlg").val(dProdLine.USINGFLG); $("#UpdDate").val(dProdLine.UPD_DATE); $("#FactoryBtn").hide(); } closeLoading(); } // 初始化 ajaxRequest({ LineId: LineId }, '../ProdLine/ProdLineInit', initCallBack); // 工厂选择 $("#FactoryBtn").click(function () { x_admin_show('工厂选择', '../Dialog/FactoryList?source=1'); }) // 工厂选择回调 window.callBackFactorylist = function (data) { $("#FactoryId").val(data.FACTORYID); $("#FactoryName").val(data.FACTORYNAME); } // 保存 $("#btnSubmit").click(function () { if (!requireCheck(false)) { return false; } layer.confirm('您确定要保存产线信息?', { btn: ['确定', '取消'] //按钮 }, function (index) { layer.close(index); loading(); //M端产线信息 var para = {}; para.LINE_ID = $("#LineId").val(); para.FACTORYID = $("#FactoryId").val(); para.LINE_NO = $("#LineNo").val(); para.LINE_NAME = $("#LineName").val(); para.RWKCODE = $("#RwkCode").val(); para.REMARK = $("#Remark").val(); para.USINGFLG = $("#UsingFlg").val(); para.UPD_DATE_OLD = $("#UpdDate").val(); //para.WEEK = $("#Week").val(); //para.MONTH = $("#Month").val(); ajaxRequest({ prodLineInfo: JSON.stringify(para) }, '../ProdLine/ProdLineAddOrUpdate', saveCallBack); }, function (index) { //取消 }); }); // 保存回调 function saveCallBack(data) { closeLoading(); if (data.success == false) { alertMessage(data.message); } else { window.parent.document.getElementById("btnQuery").click(); x_admin_close(); } } // 取消 $("#btnCancel").click(function () { Close_Dialog(); }); }) </script>
09-20
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值