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;
        /// <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事件的处理方法,进行控件重绘。如下:

        animation.AnimationComing += Animation_AnimationComing;

     private void Animation_AnimationComing(object sender, AnimationEventArgs e) { easeFunctionValue = e.NowValue; Invalidate(); }

2D电池控件自绘部分就不贴代码,代码已开源,见文章尾部。总体效果如下:

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

原文地址:https://www.cnblogs.com/james-wei/p/12904889.html