仪表控件----------WinForm控件开发系列

折月煮酒 提交于 2020-10-28 10:44:23

/// <summary>
    /// 仪表控件
    /// </summary>
    [ToolboxItem(true)]
    [DefaultProperty("Value")]
    [DefaultEvent("ValueChanged")]
    [Description("仪表控件")]
    public partial class MeterBarExt : Control
    {
        #region 事件
        public delegate void ValueEventHandler(object sender, ValueEventArgs e);

        private event ValueEventHandler valueChanged;
        /// <summary>
        /// 值更改事件
        /// </summary>
        [Description("值更改事件")]
        public event ValueEventHandler ValueChanged
        {
            add { this.valueChanged += value; }
            remove { this.valueChanged -= value; }
        }
        #endregion

        #region 属性

        #region 内圆
        private int circleRadius = 40;
        /// <summary>
        /// 控件内部圆形半径
        /// </summary>
        [DefaultValue(40)]
        [Description("控件内部圆形半径")]
        public int CircleRadius
        {
            get { return this.circleRadius; }
            set
            {
                if (this.circleRadius == value || value < 1)
                    return;
                this.circleRadius = value;
                this.Invalidate();
            }
        }

        private int arcAngle = 270;
        /// <summary>
        /// 控件弧度大小
        /// </summary>
        [DefaultValue(270)]
        [Description("控件弧度大小")]
        public int ArcAngle
        {
            get { return this.arcAngle; }
            set
            {
                if (this.arcAngle == value || value < 0 || value > 360)
                    return;
                this.arcAngle = value;
                this.Invalidate();
            }
        }
        #endregion

        #region 背景

        private bool backShow = true;
        /// <summary>
        /// 是否显示背景
        /// </summary>
        [DefaultValue(true)]
        [Description("是否显示背景")]
        public bool BackShow
        {
            get { return this.backShow; }
            set
            {
                if (this.backShow == value)
                    return;
                this.backShow = value;
                this.Invalidate();
            }
        }

        private int backBorder = 5;
        /// <summary>
        /// 背景边框大小
        /// </summary>
        [DefaultValue(5)]
        [Description("背景边框大小")]
        public int BackBorder
        {
            get { return this.backBorder; }
            set
            {
                if (this.backBorder == value || value < 0)
                    return;
                this.backBorder = value;
                this.Invalidate();
            }
        }

        private Color backBorderColor = Color.Gray;
        /// <summary>
        /// 背景边框颜色
        /// </summary>
        [DefaultValue(typeof(Color), "Gray")]
        [Description("背景边框颜色")]
        [Editor(typeof(ColorEditorExt), typeof(System.Drawing.Design.UITypeEditor))]
        public Color BackBorderColor
        {
            get { return this.backBorderColor; }
            set
            {
                if (this.backBorderColor == value)
                    return;
                this.backBorderColor = value;
                this.Invalidate();
            }
        }

        private int backShadow = 5;
        /// <summary>
        /// 背景边框阴影
        /// </summary>
        [DefaultValue(5)]
        [Description("背景边框阴影")]
        public int BackShadow
        {
            get { return this.backShadow; }
            set
            {
                if (this.backShadow == value || value < 0)
                    return;
                this.backShadow = value;
                this.Invalidate();
            }
        }

        private Color backShadowColor = Color.Gray;
        /// <summary>
        /// 背景边框阴影颜色
        /// </summary>
        [DefaultValue(typeof(Color), "Gray")]
        [Description("背景边框阴影颜色")]
        [Editor(typeof(ColorEditorExt), typeof(System.Drawing.Design.UITypeEditor))]
        public Color BackShadowColor
        {
            get { return this.backShadowColor; }
            set
            {
                if (this.backShadowColor == value)
                    return;
                this.backShadowColor = value;
                this.Invalidate();
            }
        }

        private Color backInnerColor = Color.FromArgb(220, 220, 220);
        /// <summary>
        /// 背景内容颜色
        /// </summary>
        [DefaultValue(typeof(Color), "220, 220, 220")]
        [Description("背景内容颜色")]
        [Editor(typeof(ColorEditorExt), typeof(System.Drawing.Design.UITypeEditor))]
        public Color BackInnerColor
        {
            get { return this.backInnerColor; }
            set
            {
                if (this.backInnerColor == value)
                    return;
                this.backInnerColor = value;
                this.Invalidate();
            }
        }

        #endregion

        #region 弧线

        private bool arcShow = true;
        /// <summary>
        /// 是否显示弧线
        /// </summary>
        [DefaultValue(true)]
        [Description("是否显示弧线")]
        public bool ArcShow
        {
            get { return this.arcShow; }
            set
            {
                if (this.arcShow == value)
                    return;
                this.arcShow = value;
                this.Invalidate();
            }
        }

        private int arcThickness = 5;
        /// <summary>
        /// 弧线厚度
        /// </summary>
        [DefaultValue(5)]
        [Description("弧线厚度")]
        public int ArcThickness
        {
            get { return this.arcThickness; }
            set
            {
                if (this.arcThickness == value || value < 0 || value > this.CircleRadius)
                    return;
                this.arcThickness = value;
                this.Invalidate();
            }
        }

        private bool arcRound = false;
        /// <summary>
        /// 弧线是否为圆角
        /// </summary>
        [DefaultValue(false)]
        [Description("弧线是否为圆角")]
        public bool ArcRound
        {
            get { return this.arcRound; }
            set
            {
                if (this.arcRound == value)
                    return;
                this.arcRound = value;
                this.Invalidate();
            }
        }

        private Color arcBackColor = Color.FromArgb(128, 128, 128);
        /// <summary>
        /// 弧线背景颜色
        /// </summary>
        [DefaultValue(typeof(Color), "128, 128, 128")]
        [Description("弧线背景颜色")]
        [Editor(typeof(ColorEditorExt), typeof(System.Drawing.Design.UITypeEditor))]
        public Color ArcBackColor
        {
            get { return this.arcBackColor; }
            set
            {
                if (this.arcBackColor == value)
                    return;
                this.arcBackColor = value;
                this.Invalidate();
            }
        }

        private Color arcValueColor = Color.FromArgb(154, 205, 50);
        /// <summary>
        /// 弧线值颜色
        /// </summary>
        [DefaultValue(typeof(Color), "154, 205, 50")]
        [Description("弧线值颜色")]
        [Editor(typeof(ColorEditorExt), typeof(System.Drawing.Design.UITypeEditor))]
        public Color ArcValueColor
        {
            get { return this.arcValueColor; }
            set
            {
                if (this.arcValueColor == value)
                    return;
                this.arcValueColor = value;
                this.Invalidate();
            }
        }
        #endregion

        #region 刻度

        private float scaleInterval = 20;
        /// <summary>
        /// 刻度间隔值大小
        /// </summary>
        [DefaultValue(20)]
        [Description("刻度间隔值大小")]
        public float ScaleInterval
        {
            get { return this.scaleInterval; }
            set
            {
                if (this.scaleInterval == value || value < 0f)
                    return;
                this.scaleInterval = value;
                this.Invalidate();
            }
        }

        private int scaleWidth = 3;
        /// <summary>
        /// 刻度宽度
        /// </summary>
        [DefaultValue(3)]
        [Description("刻度宽度")]
        public int ScaleWidth
        {
            get { return this.scaleWidth; }
            set
            {
                if (this.scaleWidth == value || value < 1)
                    return;
                this.scaleWidth = value;
                this.Invalidate();
            }
        }

        private int scaleHeight = 10;
        /// <summary>
        /// 刻度高度
        /// </summary>
        [DefaultValue(10)]
        [Description("刻度高度")]
        public int ScaleHeight
        {
            get { return this.scaleHeight; }
            set
            {
                if (this.scaleHeight == value)
                    return;
                this.scaleHeight = value;
                this.Invalidate();
            }
        }

        private Color scaleColor = Color.FromArgb(64, 64, 64);
        /// <summary>
        /// 刻度颜色
        /// </summary>
        [DefaultValue(typeof(Color), "64, 64, 64")]
        [Description("刻度颜色")]
        [Editor(typeof(ColorEditorExt), typeof(System.Drawing.Design.UITypeEditor))]
        public Color ScaleColor
        {
            get { return this.scaleColor; }
            set
            {
                if (this.scaleColor == value)
                    return;
                this.scaleColor = value;
                this.Invalidate();
            }
        }

        private int scaleTextRadius = 25;
        /// <summary>
        /// 刻度文本环形半径大小
        /// </summary>
        [DefaultValue(25)]
        [Description("刻度文本环形半径大小")]
        public int ScaleTextRadius
        {
            get { return this.scaleTextRadius; }
            set
            {
                if (this.scaleTextRadius == value || value < 0)
                    return;
                this.scaleTextRadius = value;
                this.Invalidate();
            }
        }

        private Color scaleTextColor = Color.FromArgb(64, 64, 64);
        /// <summary>
        /// 刻度文本颜色
        /// </summary>
        [DefaultValue(typeof(Color), "64, 64, 64")]
        [Description("刻度文本颜色")]
        [Editor(typeof(ColorEditorExt), typeof(System.Drawing.Design.UITypeEditor))]
        public Color ScaleTextColor
        {
            get { return this.scaleTextColor; }
            set
            {
                if (this.scaleTextColor == value)
                    return;
                this.scaleTextColor = value;
                this.Invalidate();
            }
        }
        #endregion

        #region 子刻度

        private bool splitScaleShow = true;
        /// <summary>
        /// 是否显示子刻度
        /// </summary>
        [DefaultValue(true)]
        [Description("是否显示子刻度")]
        public bool SplitScaleShow
        {
            get { return this.splitScaleShow; }
            set
            {
                if (this.splitScaleShow == value)
                    return;
                this.splitScaleShow = value;
                this.Invalidate();
            }
        }

        private int splitScaleWidth = 2;
        /// <summary>
        /// 子刻度宽度
        /// </summary>
        [DefaultValue(2)]
        [Description("子刻度宽度")]
        public int SplitScaleWidth
        {
            get { return this.splitScaleWidth; }
            set
            {
                if (this.splitScaleWidth == value || value < 0)
                    return;
                this.splitScaleWidth = value;
                this.Invalidate();
            }
        }

        private int splitScaleHeight = 5;
        /// <summary>
        /// 子刻度高度
        /// </summary>
        [DefaultValue(5)]
        [Description("子刻度高度")]
        public int SplitScaleHeight
        {
            get { return this.splitScaleHeight; }
            set
            {
                if (this.splitScaleHeight == value || value < 0)
                    return;
                this.splitScaleHeight = value;
                this.Invalidate();
            }
        }

        private int splitScaleCount = 5;
        /// <summary>
        /// 刻度分隔数量
        /// </summary>
        [DefaultValue(5)]
        [Description("刻度分隔数量")]
        public int SplitScaleCount
        {
            get { return this.splitScaleCount; }
            set
            {
                if (this.splitScaleCount == value || value < 0)
                    return;
                this.splitScaleCount = value;
                this.Invalidate();
            }
        }

        private Color splitScaleColor = Color.FromArgb(128, 128, 128);
        /// <summary>
        /// 子刻度颜色
        /// </summary>
        [DefaultValue(typeof(Color), "128, 128, 128")]
        [Description("子刻度颜色")]
        [Editor(typeof(ColorEditorExt), typeof(System.Drawing.Design.UITypeEditor))]
        public Color SplitScaleColor
        {
            get { return this.splitScaleColor; }
            set
            {
                if (this.splitScaleColor == value)
                    return;
                this.splitScaleColor = value;
                this.Invalidate();
            }
        }

        #endregion

        #region 渐变

        private bool gradualShow = false;
        /// <summary>
        /// 是否显示弧形渐变
        /// </summary>
        [DefaultValue(false)]
        [Description("是否显示弧形渐变")]
        public bool GradualShow
        {
            get { return this.gradualShow; }
            set
            {
                if (this.gradualShow == value)
                    return;
                this.gradualShow = value;
                this.Invalidate();
            }
        }

        private int gradualThickness = 20;
        /// <summary>
        /// 渐变弧线背景厚度
        /// </summary>
        [DefaultValue(20)]
        [Description("渐变弧线背景厚度")]
        public int GradualThickness
        {
            get { return this.gradualThickness; }
            set
            {
                if (this.gradualThickness == value || value < 0)
                    return;
                this.gradualThickness = value;
                this.Invalidate();
            }
        }

        private MeterBarColorGroupCollection gradualColorGroupCollection;
        /// <summary>
        /// 渐变颜色配置集合
        /// </summary>
        [Description("渐变颜色配置集合")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public MeterBarColorGroupCollection GradualColorGroupItems
        {
            get
            {
                if (this.gradualColorGroupCollection == null)
                    this.gradualColorGroupCollection = new MeterBarColorGroupCollection(this);
                return this.gradualColorGroupCollection;
            }
        }

        #endregion

        #region 指针
        private Color pointerColor = Color.FromArgb(107, 142, 35);
        /// <summary>
        /// 指针颜色
        /// </summary>
        [DefaultValue(typeof(Color), "107, 142, 35")]
        [Description("指针颜色")]
        [Editor(typeof(ColorEditorExt), typeof(System.Drawing.Design.UITypeEditor))]
        public Color PointerColor
        {
            get { return this.pointerColor; }
            set
            {
                if (this.pointerColor == value)
                    return;
                this.pointerColor = value;
                this.Invalidate();
            }
        }

        private Color pointerCapColor = Color.FromArgb(107, 142, 35);
        /// <summary>
        /// 针帽颜色
        /// </summary>
        [DefaultValue(typeof(Color), "107, 142, 35")]
        [Description("针帽颜色")]
        [Editor(typeof(ColorEditorExt), typeof(System.Drawing.Design.UITypeEditor))]
        public Color PointerCapColor
        {
            get { return this.pointerCapColor; }
            set
            {
                if (this.pointerCapColor == value)
                    return;
                this.pointerCapColor = value;
                this.Invalidate();
            }
        }
        #endregion

        #regionprivate bool valueShow = false;
        /// <summary>
        /// 是否显示值文本
        /// </summary>
        [DefaultValue(false)]
        [Description("是否显示值文本")]
        public bool ValueShow
        {
            get { return this.valueShow; }
            set
            {
                if (this.valueShow == value)
                    return;
                this.valueShow = value;
                this.Invalidate();
            }
        }

        private float minvalue = 0f;
        /// <summary>
        /// 最小值
        /// </summary>
        [DefaultValue(0f)]
        [Description("最小值")]
        public float MinValue
        {
            get { return this.minvalue; }
            set
            {
                if (this.minvalue == value || value >= this.MaxValue)
                    return;
                this.minvalue = value;
                this.Invalidate();
            }
        }

        private float maxvalue = 100f;
        /// <summary>
        /// 最大值
        /// </summary>
        [DefaultValue(100f)]
        [Description("最大值")]
        public float MaxValue
        {
            get { return this.maxvalue; }
            set
            {
                if (this.maxvalue == value || value <= this.MinValue)
                    return;
                this.maxvalue = value;
                this.Invalidate();
            }
        }

        private float value = 0f;
        /// <summary>
        ////// </summary>
        [DefaultValue(0f)]
        [Description("")]
        public float Value
        {
            get { return this.value; }
            set
            {
                if (this.value == value || value < this.MinValue || value > this.MaxValue)
                    return;

                this.animationTimer.Options.Data = this.value;
                this.animationValue = this.value;
                this.value = value;
                this.animationTimer.Start(true, 0);
                if (this.valueChanged != null)
                {
                    this.valueChanged(this, new ValueEventArgs() { Value = value });
                }
                this.Invalidate();
            }
        }

        private Font valueFont = new Font("宋体", 15);
        /// <summary>
        /// 值文本字体
        /// </summary>
        [DefaultValue(typeof(Font), "宋体, 15pt")]
        [Description("值文本字体")]
        public Font ValueFont
        {
            get { return this.valueFont; }
            set
            {
                if (this.valueFont == value)
                    return;
                this.valueFont = value;
                this.Invalidate();
            }
        }

        private Color valueColor = Color.FromArgb(64, 64, 64);
        /// <summary>
        /// 值文本颜色
        /// </summary>
        [DefaultValue(typeof(Color), "64, 64, 64")]
        [Description("值文本颜色")]
        [Editor(typeof(ColorEditorExt), typeof(System.Drawing.Design.UITypeEditor))]
        public Color ValueColor
        {
            get { return this.valueColor; }
            set
            {
                if (this.valueColor == value)
                    return;
                this.valueColor = value;
                this.Invalidate();
            }
        }

        #endregion

        protected override Size DefaultSize
        {
            get
            {
                return new Size(180, 180);
            }
        }

        /// <summary>
        /// 动画播放定时器
        /// </summary>
        private AnimationTimer animationTimer;

        /// <summary>
        /// 动画中指针值
        /// </summary>
        private float animationValue = 0;

        #endregion


        public MeterBarExt()
        {
            SetStyle(ControlStyles.UserPaint, true);
            SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            SetStyle(ControlStyles.ResizeRedraw, true);
            SetStyle(ControlStyles.SupportsTransparentBackColor, true);

            InitializeComponent();

            this.animationTimer = new AnimationTimer(this, new AnimationOptions());
            this.animationTimer.AT = AnimationType.EaseOut;
            this.animationTimer.Interval = 20;
            this.animationTimer.Options.AllTime = 200;
            this.animationTimer.Options.ForEverTimer = false;
            this.animationTimer.AnimationIng += new AnimationTimer.AnimationHandel(this.animationTimer_AnimationIng);
        }

        protected void animationTimer_AnimationIng(object sender, AnimationEventArgs e)
        {
            float lodValue = (float)e.Data;
            this.animationValue = (float)(lodValue + (this.Value - lodValue) * e.progressTime);
            this.Invalidate();
        }

        #region 私有
        /// <summary>
        /// 验证颜色值
        /// </summary>
        /// <param name="value"></param>
        private static int ValidRGB(int value)
        {
            if (value < 0)
                return 0;
            if (value > 255)
                return 255;
            return value;
        }

        /// <summary>
        /// 计算坐标
        /// </summary>
        /// <param name="center">圆心坐标</param>
        /// <param name="radius">圆半径</param>
        /// <param name="angle">角度</param>
        /// <returns></returns>
        private static PointF CalculatePointForAngle(PointF center, float radius, float angle)
        {
            if (radius == 0)
                return center;

            float w = 0;
            float h = 0;
            if (angle <= 90)
            {
                w = radius * (float)Math.Cos(Math.PI / 180 * angle);
                h = radius * (float)Math.Sin(Math.PI / 180 * angle);
            }
            else if (angle <= 180)
            {
                w = -radius * (float)Math.Sin(Math.PI / 180 * (angle - 90));
                h = radius * (float)Math.Cos(Math.PI / 180 * (angle - 90));

            }
            else if (angle <= 270)
            {
                w = -radius * (float)Math.Cos(Math.PI / 180 * (angle - 180));
                h = -radius * (float)Math.Sin(Math.PI / 180 * (angle - 180));
            }
            else
            {
                w = radius * (float)Math.Sin(Math.PI / 180 * (angle - 270));
                h = -radius * (float)Math.Cos(Math.PI / 180 * (angle - 270));

            }
            return new PointF(center.X + w, center.Y + h);
        }
        #endregion

        #region 重写

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            Graphics g = e.Graphics;
            g.SmoothingMode = SmoothingMode.AntiAlias;
            float start = 90 + (180 - (this.ArcAngle) / 2f);//绘制开始角度
            float border_radius = this.BackBorder + this.BackShadow + this.ScaleTextRadius + (this.GradualShow ? this.GradualThickness : this.ScaleHeight) + this.CircleRadius;//外圆半径

            RectangleF rect = RectangleF.Empty;
            PointF rect_center = PointF.Empty;
            if (this.ArcAngle > 180)
            {
                rect = new RectangleF(e.ClipRectangle.X, e.ClipRectangle.Y, e.ClipRectangle.Width, e.ClipRectangle.Height);
                rect_center = new PointF(rect.Width / 2f, rect.Height / 2f);
            }
            else
            {
                int pie_bottom_radian_left_right_height = (int)(this.CircleRadius * (2f / 5f));//扇形底部左右圆弧高度,不能写死
                int pie_bottom_radian_height = (int)(15 + (this.CircleRadius - 50) / 20f);//扇形底部圆弧高度,不能写死
                float height = border_radius + pie_bottom_radian_left_right_height + pie_bottom_radian_height;
                rect = new RectangleF(e.ClipRectangle.X, e.ClipRectangle.Y + (e.ClipRectangle.Height - height) / 2f, e.ClipRectangle.Width, e.ClipRectangle.Height);
                rect_center = new PointF(rect.X + rect.Width / 2f, rect.Y + rect.Height / 2f);
            }

            #region 背景
            if (this.BackShow)
            {
                if (this.ArcAngle > 180)//
                {
                    #region 边框
                    RectangleF circle_border_rect = new RectangleF(rect_center.X - border_radius, rect_center.Y - border_radius, border_radius * 2, border_radius * 2);
                    LinearGradientBrush circle_border_lgb = new LinearGradientBrush(circle_border_rect, Color.White, this.BackBorderColor, 45);
                    g.FillEllipse(circle_border_lgb, circle_border_rect);
                    #endregion

                    #region 内圆
                    RectangleF circle_in_rect = new RectangleF(rect_center.X - border_radius + this.BackBorder + this.BackShadow, rect_center.Y - border_radius + this.BackBorder + this.BackShadow, (border_radius - this.BackBorder - this.BackShadow) * 2, (border_radius - this.BackBorder - this.BackShadow) * 2);
                    SolidBrush circle_in_sb = new SolidBrush(this.BackInnerColor);
                    g.FillEllipse(circle_in_sb, circle_in_rect);
                    #endregion

                    #region 边框阴影
                    LinearGradientBrush circle_in_lgb = new LinearGradientBrush(circle_in_rect, Color.White, this.BackShadowColor, 225);
                    Pen circle_shadow_pen = new Pen(circle_in_lgb, this.BackShadow);
                    circle_shadow_pen.Alignment = PenAlignment.Outset;
                    g.DrawEllipse(circle_shadow_pen, circle_in_rect);
                    #endregion

                    circle_border_lgb.Dispose();
                    circle_in_sb.Dispose();
                    circle_in_lgb.Dispose();
                    circle_shadow_pen.Dispose();
                }
                else//扇形
                {
                    int pie_bottom_radian_left_right_height = (int)(this.CircleRadius * (2f / 5f));//扇形底部左右圆弧高度,不能写死
                    int pie_bottom_radian_height = (int)(15 + (this.CircleRadius - 50) / 20f);//扇形底部圆弧高度,不能写死

                    #region 边框
                    RectangleF pie_border_rect = new RectangleF(rect_center.X - border_radius, rect_center.Y - border_radius, border_radius * 2, border_radius * 2);
                    LinearGradientBrush pie_border_lgb = new LinearGradientBrush(pie_border_rect, Color.White, this.BackBorderColor, 45);

                    GraphicsPath pie_border_gp = new GraphicsPath();
                    pie_border_gp.AddArc(pie_border_rect, 180, 180);

                    pie_border_gp.AddBezier(
                    pie_border_gp.GetLastPoint(),
                    new PointF(pie_border_rect.Right, pie_border_rect.Y + pie_border_rect.Height / 2 + pie_bottom_radian_left_right_height * 1.5f + pie_bottom_radian_height),
                    new PointF(pie_border_rect.Right - pie_border_rect.Width / 2, pie_border_rect.Y + pie_border_rect.Height / 2 + pie_bottom_radian_left_right_height * 1.5f + pie_bottom_radian_height),
                    new PointF(pie_border_rect.Right - pie_border_rect.Width / 2, pie_border_rect.Y + pie_border_rect.Height / 2 + pie_bottom_radian_left_right_height * 1.5f + pie_bottom_radian_height));

                    pie_border_gp.AddBezier(
                    new PointF(pie_border_rect.X + pie_border_rect.Width / 2, pie_border_rect.Y + pie_border_rect.Height / 2 + pie_bottom_radian_left_right_height * 1.5f + pie_bottom_radian_height),
                    new PointF(pie_border_rect.X, pie_border_rect.Y + pie_border_rect.Height / 2 + pie_bottom_radian_left_right_height * 1.5f + pie_bottom_radian_height),
                    pie_border_gp.PathPoints[0],
                    pie_border_gp.PathPoints[0]);

                    pie_border_gp.CloseAllFigures();
                    g.FillPath(pie_border_lgb, pie_border_gp);
                    #endregion

                    #region 内扇形
                    RectangleF pie_in_rect = new RectangleF(rect_center.X - border_radius + this.BackBorder + this.BackShadow, rect_center.Y - border_radius + this.BackBorder + this.BackShadow, (border_radius - this.BackBorder - this.BackShadow) * 2, (border_radius - this.BackBorder - this.BackShadow) * 2);
                    SolidBrush pie_in_sb = new SolidBrush(this.BackInnerColor);

                    GraphicsPath pie_in_gp = new GraphicsPath();
                    pie_in_gp.AddArc(pie_in_rect, 180, 180);

                    pie_in_gp.AddBezier(
                    pie_in_gp.GetLastPoint(),
                    new PointF(pie_in_rect.Right, pie_in_rect.Y + pie_in_rect.Height / 2 + pie_bottom_radian_left_right_height),
                    new PointF(pie_in_rect.Right - pie_bottom_radian_left_right_height, pie_in_rect.Y + pie_in_rect.Height / 2 + pie_bottom_radian_left_right_height),
                    new PointF(pie_in_rect.Right - pie_bottom_radian_left_right_height, pie_in_rect.Y + pie_in_rect.Height / 2 + pie_bottom_radian_left_right_height));

                    pie_in_gp.AddBezier(
                    new PointF(pie_in_rect.X + pie_bottom_radian_left_right_height, pie_in_rect.Y + pie_in_rect.Height / 2 + pie_bottom_radian_left_right_height),
                    new PointF(pie_in_rect.X, pie_in_rect.Y + pie_in_rect.Height / 2 + pie_bottom_radian_left_right_height),
                    pie_in_gp.PathPoints[0],
                    pie_in_gp.PathPoints[0]);
                    pie_in_gp.CloseAllFigures();
                    g.FillPath(pie_in_sb, pie_in_gp);
                    #endregion

                    #region 边框阴影
                    LinearGradientBrush pie_in_lgb = new LinearGradientBrush(pie_in_rect, Color.White, this.BackShadowColor, 225);
                    Pen pie_shadow_pen = new Pen(pie_in_lgb, this.BackShadow);
                    pie_shadow_pen.Alignment = PenAlignment.Outset;
                    g.DrawPath(pie_shadow_pen, pie_in_gp);
                    #endregion

                    pie_border_lgb.Dispose();
                    pie_border_gp.Dispose();
                    pie_in_sb.Dispose();
                    pie_in_gp.Dispose();
                    pie_in_lgb.Dispose();
                    pie_shadow_pen.Dispose();
                }
            }
            #endregion

            #region 弧线、值弧线
            if (this.ArcShow)
            {
                RectangleF arc_rect = new RectangleF(rect_center.X - this.CircleRadius + this.ArcThickness / 2f, rect_center.Y - this.CircleRadius + this.ArcThickness / 2f, (this.CircleRadius - this.ArcThickness / 2f) * 2, (this.CircleRadius - this.ArcThickness / 2f) * 2);

                //弧线
                Pen arcback_pen = new Pen(this.ArcBackColor, this.ArcThickness);
                arcback_pen.Alignment = PenAlignment.Outset;
                g.DrawArc(arcback_pen, arc_rect, start, this.ArcAngle);

                // 值弧线背景
                Pen arcvalueback_pen = new Pen(this.ArcValueColor, this.ArcThickness);
                arcvalueback_pen.Alignment = PenAlignment.Outset;
                if (this.ArcRound)
                {
                    arcvalueback_pen.EndCap = LineCap.Round;
                }
                g.DrawArc(arcvalueback_pen, arc_rect, start, this.ArcAngle * (this.animationValue / this.MaxValue));

                arcback_pen.Dispose();
                arcvalueback_pen.Dispose();
            }
            #endregion

            #region 渐变环背景
            if (this.GradualShow && this.GradualColorGroupItems.Count > 1)
            {
                Pen gradual_pen = new Pen(Color.White, this.CircleRadius / 50f * 2f);
                int gradual_now_angle = 0;
                float item_start_angle = 0;

                for (int i = 1; i < this.GradualColorGroupItems.Count; i++)
                {
                    float color_angle = (float)this.ArcAngle * (this.GradualColorGroupItems[i].Interval - this.GradualColorGroupItems[i - 1].Interval);

                    float rgb_r = (this.GradualColorGroupItems[i].Color.R - this.GradualColorGroupItems[i - 1].Color.R) / color_angle;
                    float rgb_g = (this.GradualColorGroupItems[i].Color.G - this.GradualColorGroupItems[i - 1].Color.G) / color_angle;
                    float rgb_b = (this.GradualColorGroupItems[i].Color.B - this.GradualColorGroupItems[i - 1].Color.B) / color_angle;

                    for (int k = 0; k < color_angle; k++)
                    {
                        gradual_pen.Color = Color.FromArgb(
                        ValidRGB((int)(this.GradualColorGroupItems[i - 1].Color.R + rgb_r * k)),
                        ValidRGB((int)(this.GradualColorGroupItems[i - 1].Color.G + rgb_g * k)),
                        ValidRGB((int)(this.GradualColorGroupItems[i - 1].Color.B + rgb_b * k)));
                        gradual_now_angle = (int)(start + item_start_angle + k);
                        PointF gradual_line_start_point = CalculatePointForAngle(rect_center, this.CircleRadius, gradual_now_angle);
                        PointF gradual_line_end_point = CalculatePointForAngle(gradual_line_start_point, this.GradualThickness, gradual_now_angle);

                        g.DrawLine(gradual_pen, gradual_line_start_point, gradual_line_end_point);
                    }
                    item_start_angle += color_angle;
                }
                gradual_pen.Dispose();
            }
            #endregion

            #region 刻度线、子刻度线、刻度线文本
            StringFormat scale_sf = new StringFormat(StringFormatFlags.NoClip);
            Pen scale_pen = new Pen(this.ScaleColor, this.ScaleWidth);
            SolidBrush scale_value_sb = new SolidBrush(this.ScaleTextColor);
            Pen split_pen = new Pen(this.SplitScaleColor, this.SplitScaleWidth);
            float scale_now_angle = 0;

            int count = (int)(Math.Abs(this.MaxValue - this.MinValue) / this.ScaleInterval) + (Math.Abs(this.MaxValue - this.MinValue) % this.ScaleInterval == 0 ? 0 : 1);
            for (int i = 0; i <= count; i++)
            {
                scale_now_angle = start + this.ArcAngle / count * i;

                #region 刻度线
                PointF scale_now_start_point = CalculatePointForAngle(rect_center, this.CircleRadius, scale_now_angle);
                PointF scale_now_end_point = CalculatePointForAngle(scale_now_start_point, this.ScaleHeight, scale_now_angle);
                g.DrawLine(scale_pen, scale_now_start_point, scale_now_end_point);
                #endregion

                #region 刻度线文本
                string scale_text = (this.MinValue + this.ScaleInterval * i).ToString();
                SizeF scale_text_size = g.MeasureString(scale_text, this.Font, 0, scale_sf);
                PointF scale_text_point = CalculatePointForAngle(scale_now_start_point, (this.GradualShow && this.GradualColorGroupItems.Count > 1) ? this.GradualThickness : this.ScaleHeight, scale_now_angle);
                #region 刻度线文本坐标
                if (scale_now_angle == 0)
                {
                    scale_text_point.Y = scale_text_point.Y - scale_text_size.Height / 2;
                }
                else if (scale_now_angle < 90)
                {

                }
                else if (scale_now_angle == 90)
                {
                    scale_text_point.X = scale_text_point.X - scale_text_size.Width / 2;
                }
                else if (scale_now_angle < 180)
                {
                    scale_text_point.X = scale_text_point.X - scale_text_size.Width;
                }
                else if (scale_now_angle == 180)
                {
                    scale_text_point.Y = scale_text_point.Y - scale_text_size.Height / 2;
                    scale_text_point.X = scale_text_point.X - scale_text_size.Width;
                }
                else if (scale_now_angle < 270)
                {
                    scale_text_point.Y = scale_text_point.Y - scale_text_size.Height;
                    scale_text_point.X = scale_text_point.X - scale_text_size.Width;
                }
                else if (scale_now_angle == 270)
                {
                    scale_text_point.Y = scale_text_point.Y - scale_text_size.Height;
                    scale_text_point.X = scale_text_point.X - scale_text_size.Width / 2;
                }
                else if (scale_now_angle < 360)
                {
                    scale_text_point.Y = scale_text_point.Y - scale_text_size.Height;
                }
                #endregion

                g.DrawString(scale_text, this.Font, scale_value_sb, scale_text_point, scale_sf);
                #endregion

                #region 子刻度线
                if (SplitScaleShow)
                {

                    if (i < count)
                    {
                        for (int k = 1; k < this.SplitScaleCount; k++)
                        {
                            PointF split_now_start_point = CalculatePointForAngle(rect_center, this.CircleRadius, start + (float)this.ArcAngle / count * i + ((float)this.ArcAngle / count / this.SplitScaleCount * k));
                            PointF split_now_end_point = CalculatePointForAngle(split_now_start_point, this.SplitScaleHeight, start + (float)this.ArcAngle / count * i + ((float)this.ArcAngle / count / this.SplitScaleCount * k));
                            g.DrawLine(split_pen, split_now_start_point, split_now_end_point);
                        }
                    }
                }
                #endregion

            }
            scale_pen.Dispose();
            scale_value_sb.Dispose();
            split_pen.Dispose();
            scale_sf.Dispose();
            #endregion

            #region 指针
            SolidBrush pointer_sb = new SolidBrush(this.PointerColor);
            float pointer_now_angle = start + this.ArcAngle * (this.animationValue / this.MaxValue);
            PointF pointer_now_end_point = CalculatePointForAngle(rect_center, (float)this.CircleRadius - (this.ArcShow ? this.ArcThickness : 0f), pointer_now_angle);

            //
            int pointer_width = 8;//指针宽度
            float pointer_acutance = 20f;//指针顶端锐度
            float pointer_acutance_length = (float)(pointer_width / 2 / Math.Sin(2 * Math.PI * pointer_acutance / 360));//指针顶端锐度两边斜线长度

            GraphicsPath pointer_gp = new GraphicsPath();
            PointF[] pointer_point_arr = new PointF[] { 
            CalculatePointForAngle(pointer_now_end_point,pointer_acutance_length,pointer_now_angle-90-(90-pointer_acutance)),
            pointer_now_end_point,
            CalculatePointForAngle(pointer_now_end_point,pointer_acutance_length,pointer_now_angle-90-(90-pointer_acutance)-pointer_acutance*2),
            CalculatePointForAngle(rect_center,pointer_width/2,pointer_now_angle+90),
            CalculatePointForAngle(rect_center,pointer_width/2,pointer_now_angle-90)};
            pointer_gp.AddLines(pointer_point_arr);
            pointer_gp.CloseAllFigures();
            g.FillPath(pointer_sb, pointer_gp);

            float pointer_heart_out_radius = 10;
            float pointer_heart_in_radius = 5;

            //外针帽
            SolidBrush pointer_heart_out_sb = new SolidBrush(this.PointerCapColor);
            RectangleF pointer_heart_out_rect = new RectangleF(rect_center.X - pointer_heart_out_radius, rect_center.Y - pointer_heart_out_radius, pointer_heart_out_radius * 2, pointer_heart_out_radius * 2);
            g.FillEllipse(pointer_heart_out_sb, pointer_heart_out_rect);

            //内针帽
            RectangleF pointer_heart_in_rect = new RectangleF(rect_center.X - pointer_heart_out_radius + pointer_heart_in_radius, rect_center.Y - pointer_heart_out_radius + pointer_heart_in_radius, pointer_heart_in_radius * 2, pointer_heart_in_radius * 2);
            LinearGradientBrush pointer_heart_in_lgb = new LinearGradientBrush(pointer_heart_in_rect, Color.White, this.PointerCapColor, 225);
            g.FillEllipse(pointer_heart_in_lgb, pointer_heart_in_rect);

            pointer_sb.Dispose();
            pointer_gp.Dispose();
            pointer_heart_out_sb.Dispose();
            pointer_heart_in_lgb.Dispose();
            #endregion

            #region 值文本
            if (ValueShow)
            {
                string valueText = this.Value.ToString();
                SolidBrush text_sb = new SolidBrush(this.ValueColor);
                StringFormat text_sf = new StringFormat(StringFormatFlags.NoClip);
                SizeF text_size = g.MeasureString(valueText, this.Font);
                g.DrawString(valueText, this.Font, text_sb, new RectangleF(e.ClipRectangle.X + (rect.Width - text_size.Width) / 2f, e.ClipRectangle.Bottom - text_size.Height, text_size.Width, text_size.Height), text_sf);
                text_sb.Dispose();
                text_sf.Dispose();
            }
            #endregion

        }

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

        #endregion

        /// <summary>
        /// 值更改事件参数
        /// </summary>
        [Description("值更改事件参数")]
        public class ValueEventArgs : EventArgs
        {
            /// <summary>
            ////// </summary>
            [Description("")]
            public float Value { get; set; }
        }

        /// <summary>
        /// 渐变颜色配置集合
        /// </summary>
        [Description("渐变颜色配置集合")]
        [Editor(typeof(CollectionEditorExt), typeof(UITypeEditor))]
        public sealed class MeterBarColorGroupCollection : IList, ICollection, IEnumerable
        {
            private ArrayList groupParamList = new ArrayList();
            private MeterBarExt owner;

            public MeterBarColorGroupCollection(MeterBarExt owner)
            {
                this.owner = owner;
            }

            #region IEnumerable

            public IEnumerator GetEnumerator()
            {
                MeterBarColorGroup[] listArray = new MeterBarColorGroup[this.groupParamList.Count];
                for (int index = 0; index < listArray.Length; ++index)
                    listArray[index] = (MeterBarColorGroup)this.groupParamList[index];
                return listArray.GetEnumerator();
            }

            #endregion

            #region ICollection

            public void CopyTo(Array array, int index)
            {
                for (int i = 0; i < this.Count; i++)
                    array.SetValue(this.groupParamList[i], i + index);
            }

            public int Count
            {
                get
                {
                    return this.groupParamList.Count;
                }
            }

            public bool IsSynchronized
            {
                get
                {
                    return false;
                }
            }

            public object SyncRoot
            {
                get
                {
                    return (object)this;
                }
            }

            #endregion

            #region IList

            public int Add(object value)
            {
                MeterBarColorGroup groupParam = (MeterBarColorGroup)value;
                this.groupParamList.Add(groupParam);
                this.owner.Invalidate();
                return this.Count - 1;
            }

            public void Clear()
            {
                this.groupParamList.Clear();
                this.owner.Invalidate();
            }

            public bool Contains(object value)
            {
                return this.IndexOf(value) != -1;
            }

            public int IndexOf(object value)
            {
                return this.groupParamList.IndexOf(value);
            }

            public void Insert(int index, object value)
            {
                throw new NotImplementedException();
            }

            public bool IsFixedSize
            {
                get { return false; }
            }

            public bool IsReadOnly
            {
                get { return false; }
            }

            public void Remove(object value)
            {
                if (!(value is MeterBarColorGroup))
                    return;
                this.groupParamList.Remove((MeterBarColorGroup)value);
                this.owner.Invalidate();
            }

            public void RemoveAt(int index)
            {
                this.groupParamList.RemoveAt(index);
                this.owner.Invalidate();
            }

            public MeterBarColorGroup this[int index]
            {
                get
                {
                    return (MeterBarColorGroup)this.groupParamList[index];
                }
                set
                {
                    this.groupParamList[index] = (MeterBarColorGroup)value;
                    this.owner.Invalidate();
                }
            }

            object IList.this[int index]
            {
                get
                {
                    return (object)this.groupParamList[index];
                }
                set
                {
                    this.groupParamList[index] = (MeterBarColorGroup)value;
                    this.owner.Invalidate();
                }
            }

            #endregion

        }

    }

源码下载:仪表控件.zip

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!