Winform GDI+ 繪圖一:繪製2D電池

winform桌面軟體開發,在工業控制領域的使用還是很廣泛的。打算好好學習一下GDI+繪圖,以前都是用別人的輪子,自己也打算封裝一些工業控制領域常用的控制元件。

今天要講的是,利用緩動函式動態繪製電池。

首先在網上搜索了一些常用的緩動函式,並用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方法時,會自動扔棄上一次未完成的定時生成緩動函式值的任務。

public class Animation { private AnimationType animationType = AnimationType。EaseInOut; ///

/// 設定動畫型別 /// public AnimationType AnimationType { get => animationType; set => animationType = value; } /// /// 設定動畫持續時間 /// public int Duration { get => duration; set => duration = value; } private int duration = 200; private int span = 10; private int version = 0; public event EventHandler 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; } } /// /// 動畫開始 /// public void AnimationStart() { int number = Interlocked。Increment(ref version); ThreadPool。QueueUserWorkItem(Start, number); } /// /// 動畫結束 /// 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事件的處理方法,定時進行控制元件重繪。如下:

animation。AnimationComing += Animation_AnimationComing;private void Animation_AnimationComing(object sender, AnimationEventArgs e) { easeFunctionValue = e。NowValue; Invalidate(); }

2D電池控制元件自繪部分就不貼程式碼,程式碼已開源,見文章尾部。總體效果如下:

Winform GDI+ 繪圖一:繪製2D電池

緩動函式驅動下自繪控制元件效果圖

專案開源地址:https://gitee。com/james_happy/IndustryControls