winform桌面軟件開發,在工業控制領域的使用仍是很普遍的,打算好好學習一下GDI+繪圖。之前都是用別人的輪子,本身也打算封裝一些工業控制領域經常使用的控件。git
今天要將的是,利用緩動函數動態繪製電池。app
首先在網上搜索了一些經常使用的緩動函數,並用Animation類作了二次封裝。(引用自:http://dsqiu.iteye.com ,感謝)函數
public enum AnimationType
{
Linear,
EaseIn,
EaseOut,
EaseInOut,
BounceIn,
BounceOut,
QuadEaseOut,
QuadEaseIn,
QuadEaseInOut,
QuadEaseOutIn, //新增40種動畫效果
ExpoEaseOut, ExpoEaseIn, ExpoEaseInOut, ExpoEaseOutIn, CubicEaseOut, CubicEaseIn, CubicEaseInOut, CubicEaseOutIn, QuartEaseOut, QuartEaseIn, QuartEaseInOut, QuartEaseOutIn, QuintEaseOut, QuintEaseIn, QuintEaseInOut, QuintEaseOutIn, CircEaseOut, CircEaseIn, CircEaseInOut, CircEaseOutIn, SineEaseOut, SineEaseIn, SineEaseInOut, SineEaseOutIn, ElasticEaseOut, ElasticEaseIn, ElasticEaseInOut, ElasticEaseOutIn, BounceEaseOut, BounceEaseIn, BounceEaseInOut, BounceEaseOutIn, BackEaseOut, BackEaseIn, BackEaseInOut, BackEaseOutIn }
本身二次封裝Animation的類,對外公開一個緩動函數值改變的事件,以及動畫開始、結束的方法。學習
封裝的邏輯是,調用AnimationStart方法後,會在線程池中加入一個定時生產緩動函數對應值的方法,經過調用對外公開的事件。動畫
外部不停調用AnimationStart方法時,會自動扔棄上一次未完成的定時生產緩動函數值的任務。ui
public class Animation
{
private AnimationType animationType = AnimationType.EaseInOut; /// <summary> /// 設置動畫類型 /// </summary> public AnimationType AnimationType { get => animationType; set => animationType = value; } /// <summary> /// 設置動畫持續時間 /// </summary> public int Duration { get => duration; set => duration = value; } private int duration = 200; private int span = 10; private int version = 0; public event EventHandler<AnimationEventArgs> AnimationComing; public float GetEaseProgress(AnimationType ease_type, float linear_progress) { switch (ease_type) { case AnimationType.Linear: return linear_progress; case AnimationType.BackEaseIn: return AnimationMethod.BackEaseIn(linear_progress, 0, 1, duration); case AnimationType.BackEaseInOut: return AnimationMethod.BackEaseInOut(linear_progress, 0, 1, duration); case AnimationType.BackEaseOut: return AnimationMethod.BackEaseOut(linear_progress, 0, 1, duration); case AnimationType.BackEaseOutIn: return AnimationMethod.BackEaseOutIn(linear_progress, 0, 1, duration); case AnimationType.BounceEaseIn: return AnimationMethod.BounceEaseIn(linear_progress, 0, 1, duration); case AnimationType.BounceEaseInOut: return AnimationMethod.BounceEaseInOut(linear_progress, 0, 1, duration); case AnimationType.BounceEaseOut: return AnimationMethod.BounceEaseOut(linear_progress, 0, 1, duration); case AnimationType.BounceEaseOutIn: return AnimationMethod.BounceEaseOutIn(linear_progress, 0, 1, duration); case AnimationType.CircEaseIn: return AnimationMethod.CircEaseIn(linear_progress, 0, 1, duration); case AnimationType.CircEaseInOut: return AnimationMethod.CircEaseInOut(linear_progress, 0, 1, duration); case AnimationType.CircEaseOut: return AnimationMethod.CircEaseOut(linear_progress, 0, 1, duration); case AnimationType.CircEaseOutIn: return AnimationMethod.CircEaseOutIn(linear_progress, 0, 1, duration); case AnimationType.CubicEaseIn: return AnimationMethod.CubicEaseIn(linear_progress, 0, 1, duration); case AnimationType.CubicEaseInOut: return AnimationMethod.CubicEaseInOut(linear_progress, 0, 1, duration); case AnimationType.CubicEaseOut: return AnimationMethod.CubicEaseOut(linear_progress, 0, 1, duration); case AnimationType.CubicEaseOutIn: return AnimationMethod.CubicEaseOutIn(linear_progress, 0, 1, duration); case AnimationType.ElasticEaseIn: return AnimationMethod.ElasticEaseIn(linear_progress, 0, 1, duration); case AnimationType.ElasticEaseInOut: return AnimationMethod.ElasticEaseInOut(linear_progress, 0, 1, duration); case AnimationType.ElasticEaseOut: return AnimationMethod.ElasticEaseOut(linear_progress, 0, 1, duration); case AnimationType.ElasticEaseOutIn: return AnimationMethod.ElasticEaseOutIn(linear_progress, 0, 1, duration); case AnimationType.ExpoEaseIn: return AnimationMethod.ExpoEaseIn(linear_progress, 0, 1, duration); case AnimationType.ExpoEaseInOut: return AnimationMethod.ExpoEaseInOut(linear_progress, 0, 1, duration); case AnimationType.ExpoEaseOut: return AnimationMethod.ExpoEaseOut(linear_progress, 0, 1, duration); case AnimationType.ExpoEaseOutIn: return AnimationMethod.ExpoEaseOutIn(linear_progress, 0, 1, duration); case AnimationType.QuadEaseIn: return AnimationMethod.QuadEaseIn(linear_progress, 0, 1, duration); case AnimationType.QuadEaseInOut: return AnimationMethod.QuadEaseInOut(linear_progress, 0, 1, duration); case AnimationType.QuadEaseOut: return AnimationMethod.QuadEaseOut(linear_progress, 0, 1, duration); case AnimationType.QuadEaseOutIn: return AnimationMethod.QuadEaseOutIn(linear_progress, 0, 1, duration); case AnimationType.QuartEaseIn: return AnimationMethod.QuartEaseIn(linear_progress, 0, 1, duration); case AnimationType.QuartEaseInOut: return AnimationMethod.QuartEaseInOut(linear_progress, 0, 1, duration); case AnimationType.QuartEaseOut: return AnimationMethod.QuartEaseOut(linear_progress, 0, 1, duration); case AnimationType.QuartEaseOutIn: return AnimationMethod.QuartEaseOutIn(linear_progress, 0, 1, duration); case AnimationType.QuintEaseIn: return AnimationMethod.QuintEaseIn(linear_progress, 0, 1, duration); case AnimationType.QuintEaseInOut: return AnimationMethod.QuintEaseInOut(linear_progress, 0, 1, duration); case AnimationType.QuintEaseOut: return AnimationMethod.QuintEaseOut(linear_progress, 0, 1, duration); case AnimationType.QuintEaseOutIn: return AnimationMethod.QuintEaseOutIn(linear_progress, 0, 1, duration); case AnimationType.SineEaseIn: return AnimationMethod.SineEaseIn(linear_progress, 0, 1, duration); case AnimationType.SineEaseInOut: return AnimationMethod.SineEaseInOut(linear_progress, 0, 1, duration); case AnimationType.SineEaseOut: return AnimationMethod.SineEaseOut(linear_progress, 0, 1, duration); case AnimationType.SineEaseOutIn: return AnimationMethod.SineEaseOutIn(linear_progress, 0, 1, duration); default: return linear_progress; } } /// <summary> /// 動畫開始 /// </summary> public void AnimationStart() { int number = Interlocked.Increment(ref version); ThreadPool.QueueUserWorkItem(Start, number); } /// <summary> /// 動畫結束 /// </summary> public void AnimationStop() { Interlocked.Increment(ref version); } private void Start(object state) { try { int number = Convert.ToInt32(state); float timespan = duration / span; float currentTime = timespan; while (currentTime < duration) { if (number != version) break; Thread.Sleep((int)timespan); AnimationComing.Invoke(this, new AnimationEventArgs() { NowValue = GetEaseProgress(AnimationType, currentTime) }); currentTime += timespan; if (currentTime >= duration) { Thread.Sleep((int)(duration-currentTime)); AnimationComing.Invoke(this, new AnimationEventArgs() { NowValue = GetEaseProgress(AnimationType, currentTime) }); } } Interlocked.Decrement(ref version); } catch { } } } public class AnimationEventArgs : EventArgs { public float NowValue; }
自繪控件時,只須要註冊AnimationComing事件的處理方法,進行控件重繪。以下:this
animation.AnimationComing += Animation_AnimationComing;
private void Animation_AnimationComing(object sender, AnimationEventArgs e) { easeFunctionValue = e.NowValue; Invalidate(); }
2D電池控件自繪部分就不貼代碼,代碼已開源,見文章尾部。整體效果以下:spa