Winform GDI+ 绘图一:绘制2D电池

    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

项目开源地址:https://gitee.com/james_happy/IndustryControls线程