C#绘制常用工业控件(仪表盘,流动条,开关等)

目录

1,使用Graphics绘制Toggle。

效果:

测试代码:

Toggle控件代码:

2,使用Graphics绘制Switch。

效果:

测试代码:

Switch控件代码:

3,使用Graphics绘制PanelHead。

效果

PanelHead控件代码:

4,自定义数字键盘NumberKeyBoard。

效果:

测试代码:

NumberKeyBoard控件代码

5,使用Graphics绘制LED。

效果:

LED控件代码:

6,使用Graphics绘制流动条。

效果:

[FlowControl代码 :](#FlowControl代码 :)

7,使用Graphics绘制仪表盘1:

效果:

DashBoard控件代码

8,使用Graphics绘制仪表盘2:

效果:

Gague控件代码:


预览

1,使用Graphics绘制Toggle。

效果:
测试代码:
cs 复制代码
 private void toggle3_Click(object sender, EventArgs e)
        {
            toggle3.Checked = !toggle3.Checked;
        }
        private void toggle2_Click(object sender, EventArgs e)
        {
            toggle2.Checked = !toggle2.Checked;
        }
        private void toggle1_Click(object sender, EventArgs e)
        {
            toggle1.Checked = !toggle1.Checked;
        }
Toggle控件代码:
cs 复制代码
 [DefaultEvent("Click")]//指定默认事件
    public partial class Toggle : UserControl
    {
        public Toggle()
        {
            InitializeComponent();
            设置控件样式
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.SetStyle(ControlStyles.DoubleBuffer, true);
            this.SetStyle(ControlStyles.ResizeRedraw, true);
            this.SetStyle(ControlStyles.Selectable, true);
            this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            this.SetStyle(ControlStyles.UserPaint, true);
        }
        string falseText = "关闭";
        [Browsable(true), Category("自定义属性"), Description("false时文本")]
        public string FalseText
        {
            get
            {
                return falseText;
            }
            set
            {
                falseText = value;
                this.Invalidate();
            }
        }
        string trueText = "打开";
        [Browsable(true), Category("自定义属性"), Description("true时文本")]
        public string TrueText
        {
            get
            {
                return trueText;
            }
            set
            {
                trueText = value;
                this.Invalidate();
            }
        }
        bool _checked = false;
        [Browsable(true), Category("自定义属性"), Description("是否确认,Ture表示ON,False表示OFF")]
        public bool Checked
        {
            get
            {
                return _checked;
            }
            set
            {
                _checked = value;
                this.Invalidate();
            }
        }
        bool isShowWord = false;
        [Browsable(true), Category("自定义属性"), Description("是否显示文字,如果否则显示形状")]
        public bool IsShowWord
        {
            get
            {
                return isShowWord;
            }
            set
            {
                isShowWord = value;
                this.Invalidate();
            }
        }
        Color falseColor = Color.LightGray;
        [Browsable(true), Category("自定义属性"), Description("False状态时填充色")]
        public Color FalseColor
        {
            get
            {
                return falseColor;
            }
            set
            {
                falseColor = value;
                this.Invalidate();
            }
        }
        Color trueColor = Color.CadetBlue;
        [Browsable(true), Category("自定义属性"), Description("True状态时填充色")]
        public Color TrueColor
        {
            get
            {
                return trueColor;
            }
            set
            {
                trueColor = value;
                this.Invalidate();
            }
        }
        [Browsable(true), Category("自定义属性"), Description("若为非文字模式时,圆点的半径")]
        public int EmbellishRadius
        {
            get
            {
                return (int)(EmbellishRadiusFactor * Height);
            }
        }
        float _embellishRadiusFactor = 0.15f;
        [Browsable(true), Category("自定义属性"), Description("若为非文字模式时,圆点的比例因子")]
        public float EmbellishRadiusFactor
        {
            set
            {
                if (value >= 1 || value <= 0)
                {
                    _embellishRadiusFactor = 0.3f;
                }
                else
                {
                    _embellishRadiusFactor = value;
                }
                this.Invalidate();
            }
            get
            {
                return _embellishRadiusFactor;
            }
        }
        bool _embellishPointAuto = true;
        [Browsable(true), Category("自定义属性"), Description("修饰文字或者图形的起点是否自动获取")]
        public bool EmbellishPointAuto
        {
            get
            {
                return _embellishPointAuto;
            }
            set
            {
                _embellishPointAuto = value;
                this.Invalidate();
            }
        }
        PointF _embellishPoint;
        [Browsable(true), Category("自定义属性"), Description("绘制修饰文字或者图形所需的起点")]
        public PointF EmbellishPoint
        {
            get
            {
                return _embellishPoint;
            }
            set
            {
                _embellishPoint = value;
                if (!EmbellishPointAuto)
                {
                    this.Invalidate();
                }
            }
        }
        Color _embellishColor = Color.White;
        [Browsable(true), Category("自定义属性"), Description("绘制修饰文字或者图形所需的颜色")]
        public Color EmbellishColor
        {
            get
            {
                return _embellishColor;
            }
            set
            {
                _embellishColor = value;
                this.Invalidate();
            }
        }
        ToggleType _toggleType = ToggleType.Rectangle;
        [Browsable(true), Category("自定义属性"), Description("Toggle的样式")]
        public ToggleType ToggleStyle
        {
            get
            {
                return _toggleType;
            }
            set
            {
                _toggleType = value;
                this.Invalidate();
            }
        }
        Padding _borderRadius = new Padding(3);
        [Browsable(true), Category("自定义属性"), Description("Rectangle风格时采用的倒角半径")]
        public Padding BorderRadius
        {
            get
            {
                return _borderRadius;
            }
            set
            {
                _borderRadius = value;
                if (ToggleStyle == ToggleType.Rectangle)
                {
                    this.Invalidate();
                }
            }
        }
        int _innerGap = 3;
        [Browsable(true), Category("自定义属性"), Description("内部间隙")]
        public int InnerGap
        {
            get
            {
                return _innerGap;
            }
            set
            {
                _innerGap = value;
                this.Invalidate();
            }
        }
        Color _slidingColor = Color.White;
        [Browsable(true), Category("自定义属性"), Description("滑动块颜色")]
        public Color SlidingColor
        {
            get
            {
                return _slidingColor;
            }
            set
            {
                _slidingColor = value;
                this.Invalidate();
            }
        }
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            Graphics g = e.Graphics;
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
            g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
            GraphicsPath path = new GraphicsPath();
            Padding drawingRadius;
            if (ToggleStyle == ToggleType.Ellipse)
            {
                drawingRadius = new Padding(Height / 2);
            }
            else
            {
                drawingRadius = BorderRadius;
            }
            //绘制矩形
            //左上角
            path.AddArc(0, 0, drawingRadius.Left * 2, drawingRadius.Left * 2, 180, 90);
            //右上角
            path.AddArc(Width - drawingRadius.Top * 2, 0, drawingRadius.Top * 2, drawingRadius.Top * 2, 270, 90);
            //右下角
            path.AddArc(Width - drawingRadius.Right * 2, Height - drawingRadius.Right * 2, drawingRadius.Right * 2, drawingRadius.Right * 2, 0, 90);
            //左下角
            path.AddArc(0, Height - 2 * drawingRadius.Bottom, 2 * drawingRadius.Bottom, 2 * drawingRadius.Bottom, 90, 90);
            //滑动块起点
            Point slidingPoint;
            if (Checked)
            {
                g.FillPath(new SolidBrush(TrueColor), path);
                slidingPoint = new Point(Width - Height + InnerGap, InnerGap);
                //如果是文字模式
                if (IsShowWord && EmbellishPointAuto)
                {
                    SizeF trueTextSize = g.MeasureString(TrueText, this.Font);
                    EmbellishPoint = new PointF(((Width - trueTextSize.Width - Height)) / 2, ((Height - trueTextSize.Height)) / 2);
                }
                //如果是非文字模式
                if (!IsShowWord && EmbellishPointAuto)
                {
                    EmbellishPoint = new PointF(Height / 2 - EmbellishRadius, Height / 2 - EmbellishRadius);
                }
            }
            else
            {
                g.FillPath(new SolidBrush(FalseColor), path);
                slidingPoint = new Point(InnerGap, InnerGap);
                //如果是文字模式
                if (IsShowWord && EmbellishPointAuto)
                {
                    SizeF falseTextSize = g.MeasureString(FalseText, this.Font);
                    EmbellishPoint = new PointF(Height + (Width - Height - falseTextSize.Width) / 2, ((Height - falseTextSize.Height)) / 2);
                }
                //如果是非文字模式
                if (!IsShowWord && EmbellishPointAuto)
                {
                    EmbellishPoint = new Point(Width - (Height / 2 + EmbellishRadius / 2), Height / 2 - EmbellishRadius);
                }
            }
            int slidingWidth = Height - 2 * InnerGap;
            GraphicsPath path2 = new GraphicsPath(FillMode.Alternate);
            int slidingHeight = slidingWidth;
            float scale = slidingWidth * 1.0f / Width;
            if (ToggleStyle == ToggleType.Rectangle)
            {
                //左上角
                path2.AddArc(slidingPoint.X, slidingPoint.Y, drawingRadius.Left * 2, drawingRadius.Left * 2, 180, 90);
                //右上角
                path2.AddArc(slidingPoint.X + slidingWidth - drawingRadius.Top * 2, slidingPoint.Y, drawingRadius.Top * 2, drawingRadius.Top * 2, 270, 90);
                //右下角
                path2.AddArc(slidingPoint.X + slidingWidth - drawingRadius.Right * 2, slidingPoint.Y + slidingHeight - drawingRadius.Right * 2, drawingRadius.Right * 2, drawingRadius.Right * 2, 0, 90);
                //左下角
                path2.AddArc(slidingPoint.X, slidingPoint.Y + slidingHeight - 2 * drawingRadius.Bottom, 2 * drawingRadius.Bottom, 2 * drawingRadius.Bottom, 90, 90);
            }
            else
            {
                path2.AddEllipse(slidingPoint.X, slidingPoint.Y, Height - 2 * InnerGap, Height - 2 * InnerGap);
            }
            g.FillPath(new SolidBrush(SlidingColor), path2);
            if (IsShowWord)
            {
                if (Checked)
                {
                    g.DrawString(TrueText, this.Font, new SolidBrush(this.EmbellishColor), EmbellishPoint);
                }
                else
                {
                    g.DrawString(FalseText, this.Font, new SolidBrush(this.EmbellishColor), EmbellishPoint);
                }
            }
            else
            {
                g.DrawEllipse(new Pen(EmbellishColor, 2), new RectangleF(EmbellishPoint, new SizeF(EmbellishRadius * 2, EmbellishRadius * 2)));
            }
        }
    }
    public enum ToggleType
    {
        /// <summary>
        /// 矩形形状
        /// </summary>
        Rectangle,
        /// <summary>
        /// 椭圆形状
        /// </summary>
        Ellipse
    }

2,使用Graphics绘制Switch。

效果:
测试代码:
cs 复制代码
 private void switchControl1_Click(object sender, EventArgs e)
        {
            switchControl1.SwitchStatus = !switchControl1.SwitchStatus;
        }
Switch控件代码:
cs 复制代码
 [DefaultEvent("Click")]
    public partial class SwitchControl : UserControl
    {
        public SwitchControl()
        {
            InitializeComponent();
            设置控件样式
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.SetStyle(ControlStyles.DoubleBuffer, true);
            this.SetStyle(ControlStyles.ResizeRedraw, true);
            this.SetStyle(ControlStyles.Selectable, true);
            this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            this.SetStyle(ControlStyles.UserPaint, true);
        }
        int _outGap = 20;
        /// <summary>
        /// 外间隙
        /// </summary>
        [Browsable(true),Category("自定义属性"),Description("外间隙")]
        public int OutCap
        {
            get
            {
                return _outGap;
            }
            set
            {
                if (_outGap < 0)
                {
                    _outGap = 0;
                }
                else
                {
                    _outGap = value;
                }
                this.Invalidate();
            }
        }
        int _innerGap = 3;
        /// <summary>
        /// 内间隙
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("内间隙")]
        public int InnerCap
        {
            get
            {
                return _innerGap;
            }
            set
            {
                if (_innerGap < 0)
                {
                    _innerGap = 0;
                }
                else
                {
                    _innerGap = value;
                }
                this.Invalidate();
            }
        }
        bool _switchStatus = false;
        /// <summary>
        /// 开关状态
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("开关状态")]
        public bool SwitchStatus
        {
            get
            {
                return _switchStatus;
            }
            set
            {
                    _switchStatus = value;
                this.Invalidate();
            }
        }
        int _outCircleWidth = 4;
        /// <summary>
        /// 外圆宽度
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("外圆宽度")]
        public int OutCircleWidth
        {
            get
            {
                return _outCircleWidth;
            }
            set
            {
                if (_outCircleWidth < 0)
                {
                    _outCircleWidth = 2;
                }
                else
                {
                    _outCircleWidth = value;
                }
                this.Invalidate();
            }
        }
        Color _outCircleColor = Color.Gray;
        /// <summary>
        /// 外圆颜色
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("外圆颜色")]
        public Color OutCircleColor
        {
            get
            {
                return _outCircleColor;
            }
            set
            {
                    _outCircleColor = value;
                this.Invalidate();
            }
        }
        Color _innerCircleColor = Color.Gray;
        /// <summary>
        /// 外圆颜色
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("内圆颜色")]
        public Color InnerCircleColor
        {
            get
            {
                return _innerCircleColor;
            }
            set
            {
                _innerCircleColor = value;
                this.Invalidate();
            }
        }
        /// <summary>
        ///旋转手柄宽度
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("旋转手柄宽度")]
        public float HandleWidth
        {
            get
            {
                return Dimensions*HandleWidthFactor;
            }
        }
        float _handleWidthFactor = 0.1f;
        /// <summary>
        ///旋转手柄宽度比例因子
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("旋转手柄宽度比例因子")]
        public float HandleWidthFactor
        {
            get
            {
                return _handleWidthFactor;
            }
            set
            {
                if (_handleWidthFactor < 0)
                {
                    _handleWidthFactor = 0.15f;
                }
                else
                {
                    _handleWidthFactor = value;
                }
                this.Invalidate();
            }
        }
        Color _embellishColor = Color.Orange;
        /// <summary>
        /// 手柄标记颜色
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("手柄标记颜色")]
        public Color EmbellishColor
        {
            get
            {
                return _embellishColor;
            }
            set
            {
                _embellishColor = value;
                this.Invalidate();
            }
        }
        Color _handleColor = Color.Black;
        /// <summary>
        /// 手柄颜色
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("手柄颜色")]
        public Color HandleColor
        {
            get
            {
                return _handleColor;
            }
            set
            {
                _handleColor = value;
                this.Invalidate();
            }
        }
        /// <summary>
        /// 绘图的标准尺寸
        /// </summary>
       private int Dimensions
        {
            get
            {
                if (Width > Height)
                {
                    return Height;
                }
                else
                {
                    return Width;
                }
            }
        }
        float _sweep = 36;
        /// <summary>
        /// 手柄旋转角度
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("手柄旋转角度")]
        public float Sweep
        {
            get
            {
                return _sweep;
            }
            set
            {
                _sweep = value;
                this.Invalidate();
            }
        }
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            Graphics g = e.Graphics;
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
            g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
            //绘制外圆
            g.DrawEllipse(new Pen(OutCircleColor, OutCircleWidth), OutCap, OutCap, this.Dimensions - 2 * OutCap, Dimensions - 2 * OutCap);
            //绘制内圆
            Point innerPoint = new Point(OutCap + OutCircleWidth + InnerCap, OutCap + OutCircleWidth + InnerCap);
            int innerWidth = Dimensions - 2 * innerPoint.X ;
            g.FillEllipse(new SolidBrush(InnerCircleColor), innerPoint.X, innerPoint.Y, innerWidth, innerWidth);
            //偏移原点
            g.TranslateTransform(Dimensions / 2, Dimensions / 2);
            //旋转角度
            if (SwitchStatus)
            {
                g.RotateTransform(Sweep);
            }
            else
            {
                g.RotateTransform(-Sweep);
            }
            //绘制手柄
             g.FillRectangle(new SolidBrush(HandleColor), -HandleWidth/2, (-Dimensions + OutCap)/2, HandleWidth, Dimensions - OutCap);
            //绘制手柄标志
            float embellishWidth = HandleWidth / 2;
            float embellishHeight = HandleWidth * 1.5f;
            g.FillEllipse(new SolidBrush(EmbellishColor), -embellishWidth / 2, (-Dimensions + OutCap) / 2 + embellishWidth / 2, embellishWidth, embellishHeight);
        }
    }

3,使用Graphics绘制PanelHead。

效果

可设置边框颜色,有无,Header文字,Header高度,背景色等,以及Dock类型

PanelHead控件代码:
cs 复制代码
public partial class PanelHead : Panel
    {
        public PanelHead()
        {
            InitializeComponent();
            //  设置控件样式
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.SetStyle(ControlStyles.DoubleBuffer, true);
            this.SetStyle(ControlStyles.ResizeRedraw, true);
            this.SetStyle(ControlStyles.Selectable, true);
            this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            this.SetStyle(ControlStyles.UserPaint, true);
        }
        private Color _headerBackgroundColor = Color.SkyBlue;
        [Browsable(true), Category("自定义属性"), Description("Header背景色")]
        public Color HeaderBackgroundColor
        {
            get { return _headerBackgroundColor; }
            set
            {
                _headerBackgroundColor = value;
                this.Invalidate();
            }
        }
        private int _headerHeight = 40;
        [Browsable(true), Category("自定义属性"), Description("Header高度")]
        public int HeaderHeight
        {
            get { return _headerHeight; }
            set
            {
                _headerHeight = value;
                this.Invalidate();
            }
        }
        private Color _headerForeColor = Color.Black;
        [Browsable(true), Category("自定义属性"), Description("Header前景色")]
        public Color HeaderForeColor
        {
            get { return _headerForeColor; }
            set
            {
                _headerForeColor = value;
                this.Invalidate();
            }
        }
        private string _headerText="标题";
        [Browsable(true), Category("自定义属性"), Description("Header前景色")]
        public string HeaderText
        {
            get { return _headerText; }
            set
            {
                _headerText = value;
                this.Invalidate();
            }
        }
        private Font _headerFont = DefaultFont;
        [Browsable(true), Category("自定义属性"), Description("Header文字字体")]
        public Font HeaderFont
        {
            get { return _headerFont; }
            set
            {
                _headerFont = value;
                this.Invalidate();
            }
        }
        private StringAlignment _headerTextAlignment = StringAlignment.Center;
        [Browsable(true), Category("自定义属性"), Description("Header文字水平对齐方式")]
        public StringAlignment HeaderTextAlignment
        {
            get { return _headerTextAlignment; }
            set
            {
                _headerTextAlignment = value;
                this.Invalidate();
            }
        }
        private StringAlignment _headerTextLineAlignment = StringAlignment.Center;
        [Browsable(true), Category("自定义属性"), Description("Header文字垂直对齐方式")]
        public StringAlignment HeaderTextLineAlignment
        {
            get { return _headerTextLineAlignment; }
            set
            {
                _headerTextLineAlignment = value;
                this.Invalidate();
            }
        }
        private bool _hasBorder = true;
        [Browsable(true), Category("自定义属性"), Description("是否有外边框")]
        public bool HasBorder
        {
            get { return _hasBorder; }
            set
            {
                _hasBorder = value;
                this.Invalidate();
            }
        }
        private Color _borderColor = Color.Black;
        [Browsable(true), Category("自定义属性"), Description("外边框颜色")]
        public Color BorderColor
        {
            get { return _borderColor; }
            set
            {
                _borderColor = value;
                this.Invalidate();
            }
        }
        private int _borderWidth = 1;
        [Browsable(true), Category("自定义属性"), Description("外边框的宽度")]
        public int BorderWidth
        {
            get { return _borderWidth; }
            set
            {
                _borderWidth = value;
                this.Invalidate();
            }
        }
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            Graphics g = e.Graphics;
            g.SmoothingMode = SmoothingMode.AntiAlias; //使绘图质量最高,即消除锯齿
            g.InterpolationMode = InterpolationMode.HighQualityBicubic;
            g.CompositingQuality = CompositingQuality.HighQuality;
            g.FillRectangle(new SolidBrush(HeaderBackgroundColor), OriginPoint.X, OriginPoint.Y, DimensionsWidth, HeaderHeight);
            StringFormat format = new StringFormat()
            {
                Alignment = this.HeaderTextAlignment,
                LineAlignment = HeaderTextLineAlignment
            };
            g.DrawString(HeaderText, HeaderFont, new SolidBrush(HeaderForeColor), new RectangleF(OriginPoint.X, OriginPoint.Y, DimensionsWidth, HeaderHeight), format);
            //绘制边框
            if (HasBorder)
            {
                g.DrawRectangle(new Pen(BorderColor, BorderWidth), BorderWidth / 2, BorderWidth / 2, Width - BorderWidth, Height - BorderWidth);
            }
        }
        int DimensionsWidth
        {
            get
            {
                if (HasBorder)
                {
                    return Width - BorderWidth-2;
                }
                return Width;
            }
        }
        int DimensionsHeight
        {
            get
            {
                if (HasBorder)
                {
                    return Height - BorderWidth-2;
                }
                return Height;
            }
        }
        Point OriginPoint
        {
            get
            {
                if (HasBorder)
                {
                    return new Point(BorderWidth, BorderWidth);
                }
                return new Point(0, 0);
            }
        }
        Dictionary<Control, Rectangle> dic = new Dictionary<Control, Rectangle>();
        int flag = 0xff;
        protected override void OnLayout(LayoutEventArgs e)
        {
            if (HasChildren)
            {
                foreach (Control item in this.Controls)
                {
                    switch (item.Dock)
                    {
                        case DockStyle.None:
                            item.SuspendLayout();
                            if (dic.ContainsKey(item) && !((flag & 0x1) == 1))
                            {
                                item.Bounds = dic[item];
                                flag = 0xff;
                            }
                            item.ResumeLayout();
                            //  base.OnLayout(e);
                            break;
                        case DockStyle.Top:
                            if ((flag & 0x1) == 1)
                            {
                                dic[item] = item.Bounds;
                                flag = flag & 0xfe;
                            }
                            if ((flag & 0x2) == 2)
                            {
                                item.Bounds = dic[item];
                                flag = flag & 0xfd;
                            }
                            item.SuspendLayout();
                            if (item.Height <= DimensionsHeight - HeaderHeight)
                            {
                                item.SetBounds(OriginPoint.X, OriginPoint.Y + HeaderHeight, DimensionsWidth, item.Height);
                            }
                            else
                            {
                                item.SetBounds(OriginPoint.X, OriginPoint.Y + HeaderHeight, DimensionsWidth, DimensionsHeight - HeaderHeight);
                            }
                            break;
                        case DockStyle.Bottom:
                            if ((flag & 0x1) == 1)
                            {
                                dic[item] = item.Bounds;
                                flag = flag & 0xfe;
                            }
                            if ((flag & 0x4) == 4)
                            {
                                item.Bounds = dic[item];
                                flag = flag & 0xfb;
                            }
                            item.SuspendLayout();
                            if (item.Height <= DimensionsHeight - HeaderHeight)
                            {
                                item.SetBounds(OriginPoint.X,OriginPoint.Y+ DimensionsHeight -item.Height, DimensionsWidth, item.Height);
                            }
                            else
                            {
                                item.SetBounds(OriginPoint.X, OriginPoint.Y + HeaderHeight, DimensionsWidth, DimensionsHeight - HeaderHeight);
                            }
                            break;
                        case DockStyle.Left:
                            if ((flag & 0x1) == 1)
                            {
                                dic[item] = item.Bounds;
                                flag = flag & 0xfe;
                            }
                            if ((flag & 0x8) == 8)
                            {
                                item.Bounds = dic[item];
                                flag = flag & 0xf7;
                            }
                            item.SuspendLayout();
                            if (item.Width <= DimensionsWidth)
                            {
                                item.SetBounds(OriginPoint.X, OriginPoint.Y + HeaderHeight, item.Width, DimensionsHeight - HeaderHeight);
                            }
                            else
                            {
                                item.SetBounds(OriginPoint.X, OriginPoint.Y + HeaderHeight, DimensionsWidth, Height - HeaderHeight);
                            }
                            break;
                        case DockStyle.Right:
                            if ((flag & 0x1) == 1)
                            {
                                dic[item] = item.Bounds;
                                flag = flag & 0xfe;
                            }
                            if ((flag & 0x10) == 16)
                            {
                                item.Bounds = dic[item];
                                flag = flag & 0xef;
                            }
                            item.SuspendLayout();
                            if (item.Width <= DimensionsWidth)
                            {
                                item.SetBounds(OriginPoint.X + DimensionsWidth - item.Width, OriginPoint.Y + HeaderHeight, item.Width, DimensionsHeight - HeaderHeight);
                            }
                            else
                            {
                                item.SetBounds(OriginPoint.X, OriginPoint.Y + HeaderHeight, DimensionsWidth, Height - HeaderHeight);
                            }
                            break;
                        case DockStyle.Fill:
                            if ((flag & 0x1) == 1)
                            {
                                dic[item] = item.Bounds;
                                flag = flag & 0xfe;
                            }
                            item.SuspendLayout();
                            item.SetBounds(OriginPoint.X, OriginPoint.Y + HeaderHeight, DimensionsWidth, DimensionsHeight - HeaderHeight);
                            break;
                        default:
                            break;
                    }
                }
            }
        }
    }

4,自定义数字键盘NumberKeyBoard。

效果:
测试代码:
cs 复制代码
public Form2()
        {
            InitializeComponent();
            //接收输入完成的数据
            numKeyBoard1.InputCompleted += NumKeyBoard1_InputCompleted1;
            //Esc事件
            numKeyBoard1.InputCancel += NumKeyBoard1_InputCancel;
        }
        private void Form2_Load(object sender, EventArgs e)
        {
            //注册哪些控件使用数字键盘,通过控件名进行注册,如果不注册将无数字键盘弹出
            numKeyBoard1.RegisterNumberKeyBoard(new string[] { "textBox1", "textBox2", "textBox3" });
        }
        private void NumKeyBoard1_InputCancel(object sender, EventArgs e)
        {
            //键盘的打开是通过目的控件的GotFocus事件完成如果不将焦点转移到其他控件,将影响在该目的控件上重复打开键盘
            this.ActiveControl = button1;
            
        }

        private void NumKeyBoard1_InputCompleted1(object sender, CustomControl.NumKeyBoardEventArgs e)
        {
            Control control = e.TargetControl;
            float value = e.Value;
            if(control is TextBox)
            {
                control.Text = value.ToString();
            }
            this.ActiveControl=button1;
        }
NumberKeyBoard控件代码
cs 复制代码
 public partial class NumKeyBoard : UserControl
    {
        public NumKeyBoard()
        {
            InitializeComponent();
            InitLoad();
        }
        /// <summary>
        /// 数字键盘输入完成
        /// </summary>
        public event EventHandler<NumKeyBoardEventArgs> InputCompleted;
        /// <summary>
        /// 输入取消事件
        /// </summary>
        public event EventHandler InputCancel;
        List<Control> targetControls = new List<Control>();
        void InitLoad()
        {
            lblTitle.MouseMove += NumKeyBoard_MouseMove;
            lblTitle.MouseDown += NumKeyBoard_MouseDown;
            lblTitle.MouseUp += NumKeyBoard_MouseUp;
            foreach (Control item in tableLayoutKeyBoard.Controls)
            {
                if (item is Button)
                {
                    (item as Button).Click += NumKeyBoard_Click;
                }
            }

        }
        Control curControl;
        private void TargetControl_GotFocus(object sender, EventArgs e)
        {
            this.Visible = true;
            this.BringToFront();
            curControl = sender as Control;
            if (sender is TextBox)
            {
                TextBox tb = sender as TextBox;
                lblDisplay.Text = tb.Text;
                //设置键盘出现位置
                Point tbPoint = tb.Location;
                Point p = new Point();
                if (tbPoint.Y + this.Height < tb.TopLevelControl.Height || tbPoint.Y < this.Height)
                {
                    p.Y = tbPoint.Y + 2 + tb.Height;
                }
                else
                {
                    p.Y = tbPoint.Y - this.Height - 2;
                }
                if (this.Width > tb.TopLevelControl.Width - tbPoint.X)
                {
                    p.X = tbPoint.X + tb.Width - this.Width;
                }
                else
                {
                    p.X = tbPoint.X + 2;
                }

                this.Location = p;
            }
        }
        #region 键盘移动
        Point offsetPoint;
        bool canMove = false;
        private void NumKeyBoard_MouseUp(object sender, MouseEventArgs e)
        {
            canMove = false;
        }
        private void NumKeyBoard_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                canMove = true;
                offsetPoint = new Point(-e.X, -e.Y);
            }
        }
        private void NumKeyBoard_MouseMove(object sender, MouseEventArgs e)
        {
            if (canMove)
            {
                Point curPoint = this.Parent.PointToClient(Control.MousePosition);
                curPoint.Offset(offsetPoint);
                this.Location = curPoint;
            }
        }
        #endregion

        private void NumKeyBoard_Click(object sender, EventArgs e)
        {
            string key = (sender as Button).Text.Trim().ToLower();
            lblTitle.Text = "";
            switch (key)
            {
                case "-":
                    if (lblDisplay.Text.StartsWith("-"))
                    {
                        lblDisplay.Text = lblDisplay.Text.Remove(0, 1);
                    }
                    else
                    {
                        lblDisplay.Text = lblDisplay.Text.Insert(0, "-");
                    }
                    break;
                case "del":
                    if (lblDisplay.Text.Length > 0)
                    {
                        lblDisplay.Text = lblDisplay.Text.Remove(lblDisplay.Text.Length - 1, 1);
                    }
                    break;
                case "esc":
                    lblDisplay.Text = "";
                    InputCancel?.Invoke(this, null);
                    this.Visible = false;
                    break;
                case ".":
                    if (lblDisplay.Text.IndexOf('.') != -1)
                    {
                        return;
                    }
                    if (string.IsNullOrEmpty(lblDisplay.Text))
                    {
                        lblDisplay.Text = "0.";
                        return;
                    }
                    lblDisplay.Text += ".";
                    break;
                case "0":
                    if (lblDisplay.Text.Equals("0"))
                    {
                        return;
                    }
                    lblDisplay.Text += "0";
                    break;
                case "enter":
                    try
                    {
                        float value = float.Parse(lblDisplay.Text.Trim());
                        if (value < MinNum || value > MaxNum)
                        {
                            lblTitle.Text = $"数值只能位于 {MinNum}~{MaxNum} 之间";
                            System.Media.SystemSounds.Hand.Play();
                            return;
                        }
                        lblDisplay.Text = "";
                        InputCompleted?.Invoke(this, new NumKeyBoardEventArgs(curControl, value));
                        this.Visible = false;
                    }
                    catch (Exception ex)
                    {
                        lblTitle.Text = ex.Message;
                    }


                    break;
                default:
                    if (lblDisplay.Text.Equals("0"))
                    {
                        lblDisplay.Text = "";
                    }
                    lblDisplay.Text += key;
                    break;
            }
        }
        float _minNum = 0;
        [Browsable(true), Category("自定义属性"), Description("最小值")]
        public float MinNum
        {
            get
            {
                return _minNum;
            }
            set
            {
                if (_minNum > MaxNum)
                {
                    _minNum = MaxNum;
                }
                else
                {
                    _minNum = value;
                }
                lblMinNum.Text = _minNum.ToString();
                this.Invalidate();
            }
        }
        float _maxNum = 1000;
        [Browsable(true), Category("自定义属性"), Description("最小值")]
        public float MaxNum
        {
            get
            {
                return _maxNum;
            }
            set
            {
                if (_maxNum < MinNum)
                {
                    _maxNum = MinNum;
                }
                else
                {
                    _maxNum = value;
                }
                lblMaxNum.Text = _maxNum.ToString();
                this.Invalidate();
            }
        }
        /// <summary>
        /// 为指定控件添加数字键盘
        /// </summary>
        /// <param name="targetControlNames">需要添加数字键盘的控件名集合</param>
        public void RegisterNumberKeyBoard(string[] targetControlNames)
        {
            if (targetControlNames != null && targetControlNames.Length != 0)
            {
                GetControlByControlName(this.TopLevelControl, targetControlNames);
            }
            foreach (var item in targetControls)
            {
                if (item is TextBox)
                {
                    //给该控件注册获取光标事件
                    (item as TextBox).GotFocus += TargetControl_GotFocus;
                }
            }
        }
        /// <summary>
        ///根据目标控件名获取控件集合
        /// </summary>
        /// <param name="control"></param>
        void GetControlByControlName(Control control, string[] targetNames)
        {
            if (targetNames.FirstOrDefault(item => item.Equals(control.Name)) != null)
            {
                targetControls.Add(control);
            }
            if (control.HasChildren)
            {
                foreach (Control c in control.Controls)
                {
                    GetControlByControlName(c, targetNames);
                }
            }
        }
    }
    public class NumKeyBoardEventArgs : EventArgs
    {

        public NumKeyBoardEventArgs(Control targetControl, float val)
        {
            this.TargetControl = targetControl;
            this.Value = val;
        }
        /// <summary>
        /// 目标控件
        /// </summary>
        public Control TargetControl { get; private set; }
        /// <summary>
        /// 数字键盘输入的值
        /// </summary>
        public float Value { get; private set; }
    }

5,使用Graphics绘制LED。

效果:
LED控件代码:
cs 复制代码
  public partial class LED : UserControl
    {
        public LED()
        {
            InitializeComponent();
            设置控件样式
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.SetStyle(ControlStyles.DoubleBuffer, true);
            this.SetStyle(ControlStyles.ResizeRedraw, true);
            this.SetStyle(ControlStyles.Selectable, true);
            this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            this.SetStyle(ControlStyles.UserPaint, true);
        }
        float outEllipseWidth = 5;
        [Browsable(true), Category("自定义属性"), Description("外圆的宽度")]
        public float OutEllipseWidth
        {
            get
            {
                return outEllipseWidth;
            }
            set
            {
                if (value < 0)
                {
                    outEllipseWidth = 2;
                }
                else
                {
                    outEllipseWidth = value;
                }
                this.Invalidate();
            }
        }
        Color outEllipseColor = Color.Lime;
        [Browsable(true), Category("自定义属性"), Description("外圆的颜色")]
        public Color OutEllipseColor
        {
            get
            {
                return outEllipseColor;
            }
            set
            {
                outEllipseColor = value;
                this.Invalidate();
            }
        }
        float outGapWidth = 3;
        [Browsable(true), Category("自定义属性"), Description("外间隙宽度")]
        public float OutCapWidth
        {
            get
            {
                return outGapWidth;
            }
            set
            {
                if (value < 0)
                {
                    outGapWidth = 2;
                }
                else
                {
                    outGapWidth = value;
                }
                this.Invalidate();
            }
        }
        Color centerEllipseColor = Color.Lime;
        [Browsable(true), Category("自定义属性"), Description("中心圆的颜色")]
        public Color CenterEllipseColor
        {
            get
            {
                return centerEllipseColor;
            }
            set
            {
                centerEllipseColor = value;
                this.Invalidate();
            }
        }
        protected override void OnPaint(PaintEventArgs e)
        {

            base.OnPaint(e);
            Graphics g = e.Graphics;
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
            g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
            //绘制外圆
            g.DrawEllipse(new Pen(OutEllipseColor, OutEllipseWidth), OutEllipseWidth, OutEllipseWidth, Width - OutEllipseWidth * 2, Height - OutEllipseWidth * 2);
            //绘制内圆
            PointF p = new PointF((float)(1.5 * OutEllipseWidth) + OutCapWidth, (float)(1.5 * OutEllipseWidth) + OutCapWidth);
            float centerWidth = Width - (float)(2 * (1.5 * OutEllipseWidth + OutCapWidth));
            float centerHeight = Height - (float)(2 * (1.5 * OutEllipseWidth + OutCapWidth));
            RectangleF centerRec = new RectangleF(p,new SizeF(centerWidth,centerHeight));
            g.FillEllipse(new SolidBrush(CenterEllipseColor), centerRec);
        }
    }

6,使用Graphics绘制流动条。

效果:

F

FlowControl代码 :
cs 复制代码
 public partial class FlowControl : UserControl
    {
        private float startOffset = 0.0f;
        private Timer mytimer = new Timer();
        Graphics g;
        public FlowControl()
        {
            InitializeComponent();
            设置控件样式
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.SetStyle(ControlStyles.DoubleBuffer, true);
            this.SetStyle(ControlStyles.ResizeRedraw, true);
            this.SetStyle(ControlStyles.Selectable, true);
            this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            this.SetStyle(ControlStyles.UserPaint, true);
            mytimer.Interval = 50;
            mytimer.Tick += Mytimer_Tick;
            mytimer.Start();
        }
        private void Mytimer_Tick(object sender, EventArgs e)
        {
            startOffset += moveSpeed;
            if (Math.Abs(startOffset) > BarLength + GapLength)
            {
                startOffset = 0;
            }
            this.Invalidate();
        }
        #region Fileds
        private int barHeight = 5;
        [Browsable(true), Category("自定义属性"), Description("流动条宽度")]
        public int BarHeight
        {
            get { return barHeight; }
            set
            {
                this.barHeight = value;
                base.Invalidate();
            }
        }
        private Color barColor = Color.DodgerBlue;
        [Browsable(true), Category("自定义属性"), Description("获取或设置管道控件的流动块颜色")]
        public Color BarColor
        {
            get
            {
                return this.barColor;
            }
            set
            {
                this.barColor = value;
                base.Invalidate();
            }
        }
        private Color borderColor = Color.DimGray;
        [Browsable(true), Category("自定义属性"), Description("获取或设置管道边线颜色")]
        public Color BorderColor
        {
            get
            {
                return this.borderColor;
            }
            set
            {
                this.borderColor = value;
                base.Invalidate();
            }
        }
        private float borderWidth = 1;
        [Browsable(true), Category("自定义属性"), Description("获取或设置管道壁厚度")]
        public float BorderWidth
        {
            get
            {
                return this.borderWidth;
            }
            set
            {
                this.borderWidth = value;
                base.Invalidate();
            }
        }
        private Color pipeEdgeColor = Color.DimGray;
        [Browsable(true), Category("自定义属性"), Description("获取或设置管道边缘颜色")]
        public Color PipeEdgeColor
        {
            get
            {
                return this.pipeEdgeColor;
            }
            set
            {
                this.pipeEdgeColor = value;
                base.Invalidate();
            }
        }
        private Color pipeCenterColor = Color.LightGray;
        [Browsable(true), Category("自定义属性"), Description("获取或设置管道控件的中心颜色")]
        public Color PipeCenterColor
        {
            get
            {
                return this.pipeCenterColor;
            }
            set
            {
                this.pipeCenterColor = value;
                base.Invalidate();
            }
        }
        private PipeTurnDirection pipeTurnLeft = PipeTurnDirection.None;
        [Browsable(true), Category("自定义属性"), Description("左管道的转向类型")]
        public PipeTurnDirection PipeTurnLeft
        {
            get
            {
                return this.pipeTurnLeft;
            }
            set
            {
                this.pipeTurnLeft = value;
                base.Invalidate();
            }
        }
        private PipeTurnDirection pipeTurnRight = PipeTurnDirection.None;
        [Browsable(true), Category("自定义属性"), Description("右管道的转向类型")]
        public PipeTurnDirection PipeTurnRight
        {
            get
            {
                return this.pipeTurnRight;
            }
            set
            {
                this.pipeTurnRight = value;
                base.Invalidate();
            }
        }
        private DirectionStyle pipeLineDirection = DirectionStyle.Horizontal;
        [Browsable(true), Category("自定义属性"), Description("设置管道是横向的还是纵向的")]
        public DirectionStyle PipeLineDirection
        {
            get
            {
                return this.pipeLineDirection;
            }
            set
            {
                this.pipeLineDirection = value;
                int temp;
                if (value == DirectionStyle.Horizontal)
                {
                    temp = Height;
                    Height = Width;
                    Width = temp;
                }
                else
                {
                    temp = Width;
                    Width = Height;
                    Height = temp;
                }
                base.Invalidate();
            }
        }
        private bool isActive = false;
        [Browsable(true), Category("自定义属性"), DefaultValue(false), Description("获取或设置管道线是否激活液体显示")]
        public bool IsActive
        {
            get
            {
                return this.isActive;
            }
            set
            {
                this.isActive = value;
                this.mytimer.Enabled = value;
                base.Invalidate();
            }
        }
        private float moveSpeed = 0.3f;
        [Browsable(true), Category("自定义属性"), Description("管道线液体流动的速度,0为静止,正数为正向流动,负数为反向流动")]
        public float MoveSpeed
        {
            get
            {
                return this.moveSpeed;
            }
            set
            {
                this.moveSpeed = value;
                base.Invalidate();
            }
        }
        private int barLength = 5;
        [Browsable(true), Category("自定义属性"), Description("流动条长度")]
        public int BarLength
        {
            get
            {
                return this.barLength;
            }
            set
            {
                this.barLength = value;
                base.Invalidate();
            }
        }
        private int gapLength = 5;
        [Browsable(true), Category("自定义属性"), Description("间隙长度")]
        public int GapLength
        {
            get
            {
                return this.gapLength;
            }
            set
            {
                this.gapLength = value;
                base.Invalidate();
            }
        }
        #endregion
        protected override void OnResize(EventArgs e)
        {
            if (PipeLineDirection == DirectionStyle.Horizontal)
            {
                if (Width < 2 * Height)
                {
                    Width = 2 * Height;
                }
            }
            else
            {
                if (Height < 2 * Width)
                {
                    Height = 2 * Width;
                }
            }
            base.OnResize(e);
        }
        protected override void OnPaint(PaintEventArgs e)
        {
            //  base.OnPaint(e);
            g = e.Graphics;
            Rectangle rec;
            Rectangle rec2;
            GraphicsPath graphicsPath = new GraphicsPath();
            if (PipeLineDirection == DirectionStyle.Horizontal)
            {
                #region 水平
                switch (pipeTurnLeft)
                {
                    case PipeTurnDirection.Up:
                        rec = new Rectangle(0, -Height, 2 * Height, 2 * Height);
                        rec2 = new Rectangle(rec.X + (int)BorderWidth / 2, rec.Y, rec.Width - (int)BorderWidth, rec.Height - (int)BorderWidth / 2);
                        PaintElliple(g, rec, rec2, 90, 90);
                        // path.AddArc(new Rectangle( Height / 2, rec.Y /2, Height , Height), 90, 90);
                        //特别需要注意角度旋转方向,如果角度旋转方向选错就形成闭环
                        graphicsPath.AddArc(new Rectangle(this.Height / 2, this.Height / 2 * (-1) - 1, this.Height, this.Height), 180.0f, -90.0f);
                        break;
                    case PipeTurnDirection.Down:
                        rec = new Rectangle(0, 0, 2 * Height, 2 * Height);
                        rec2 = new Rectangle(rec.X + (int)BorderWidth / 2, rec.Y + (int)BorderWidth / 2, rec.Width - (int)BorderWidth, rec.Height - (int)BorderWidth / 2);
                        PaintElliple(g, rec, rec2, 180, 90);
                        graphicsPath.AddArc(new Rectangle(Height / 2, Height / 2, Height, Height), 180, 90);
                        break;
                    case PipeTurnDirection.Left:
                    case PipeTurnDirection.Right:
                    case PipeTurnDirection.None:
                        PointF[] points = new PointF[] { new PointF(Height, BorderWidth / 2), new PointF(0, BorderWidth / 2), new PointF(0, Height - BorderWidth / 2), new PointF(Height, Height - BorderWidth / 2) };
                        PaintRectangle(g, new Rectangle(0, 0, Height, Height), points);
                        graphicsPath.AddLine(new PointF(0, Height / 2), new PointF(Height, Height / 2));
                        break;
                    default:
                        break;
                }
                switch (PipeTurnRight)
                {
                    case PipeTurnDirection.Up:
                        rec = new Rectangle(Width - 2 * Height, -Height, 2 * Height, 2 * Height);
                        rec2 = new Rectangle(rec.X + (int)BorderWidth / 2, rec.Y, rec.Width - (int)BorderWidth, rec.Height - (int)BorderWidth / 2);
                        PaintElliple(g, rec, rec2, 0, 90);
                        graphicsPath.AddArc(new Rectangle(rec.X + Height / 2, rec.Y / 2, Height, Height), 90, -90);
                        break;
                    case PipeTurnDirection.Down:
                        rec = new Rectangle(Width - 2 * Height, 0, 2 * Height, 2 * Height);
                        rec2 = new Rectangle(rec.X, rec.Y + (int)BorderWidth / 2, rec.Width - (int)BorderWidth / 2, rec.Height - (int)BorderWidth / 2);
                        PaintElliple(g, rec, rec2, 270, 90);
                        //特别需要注意角度旋转方向,如果角度旋转方向选错就形成闭环
                        graphicsPath.AddArc(new Rectangle(rec.X + Height / 2, Height / 2, Height, Height), 270, 90);
                        break;
                    case PipeTurnDirection.Left:
                    case PipeTurnDirection.Right:
                    case PipeTurnDirection.None:
                        PointF[] points = new PointF[] { new PointF(Width - Height, BorderWidth / 2), new PointF(Width, BorderWidth / 2), new PointF(Width, Height - BorderWidth / 2), new PointF(Width - Height, Height - BorderWidth / 2) };
                        PaintRectangle(g, new Rectangle(Width - Height, 0, Height, Height), points);
                        graphicsPath.AddLine(Width - Height, Height / 2, Width, Height / 2);
                        break;
                    default:
                        break;
                }
                if (Width > Height * 2)
                {
                    PointF[] points = new PointF[] { new PointF(Height, BorderWidth / 2), new PointF(Width - Height, BorderWidth / 2), new PointF(Height, Height - BorderWidth / 2), new PointF(Width - Height, Height - BorderWidth / 2) };
                    PaintRectangle(g, new Rectangle(Height, 0, Width - 2 * Height, Height), points);
                    //  graphicsPath.AddLine(Height, Height / 2,Width- Height , Height / 2);
                }
                #endregion
            }
            else
            {
                //垂直
                switch (pipeTurnLeft)
                {
                    case PipeTurnDirection.Left:
                        rec = new Rectangle(-Width, 0, 2 * Width, 2 * Width);
                        rec2 = new Rectangle(rec.X, rec.Y + (int)BorderWidth / 2, rec.Width - (int)BorderWidth / 2, rec.Height - (int)BorderWidth);
                        PaintElliple(g, rec, rec2, 270, 90);
                        // path.AddArc(new Rectangle( Height / 2, rec.Y /2, Height , Height), 90, 90);
                        //特别需要注意角度旋转方向,如果角度旋转方向选错就形成闭环
                        graphicsPath.AddArc(new Rectangle(-this.Width / 2, this.Width / 2, this.Width, this.Width), 270.0f, 90.0f);
                        break;
                    case PipeTurnDirection.Right:
                        rec = new Rectangle(0, 0, 2 * Width, 2 * Width);
                        rec2 = new Rectangle(rec.X + (int)BorderWidth / 2, rec.Y + (int)BorderWidth / 2, rec.Width - (int)BorderWidth, rec.Height - (int)BorderWidth / 2);
                        PaintElliple(g, rec, rec2, 180, 90);
                        graphicsPath.AddArc(new Rectangle(Width / 2, Width / 2, Width, Width), 270, -90);
                        break;
                    case PipeTurnDirection.Up:
                    case PipeTurnDirection.Down:
                    case PipeTurnDirection.None:
                        PointF[] points = new PointF[] { new PointF(BorderWidth / 2, 0), new PointF(BorderWidth / 2, Width), new PointF(Width - BorderWidth / 2, 0), new PointF(Width - BorderWidth / 2, Width) };
                        PaintRectangle(g, new Rectangle(0, 0, Width, Width), points, LinearGradientMode.Horizontal);
                        graphicsPath.AddLine(new PointF(Width / 2, 0), new PointF(Width / 2, Width));
                        break;
                    default:
                        break;
                }
                switch (PipeTurnRight)
                {
                    case PipeTurnDirection.Left:
                        rec = new Rectangle(-Width, Height - 2 * Width, 2 * Width, 2 * Width);
                        rec2 = new Rectangle(rec.X, rec.Y + (int)BorderWidth / 2, rec.Width - (int)BorderWidth / 2, rec.Height - (int)BorderWidth);
                        PaintElliple(g, rec, rec2, 0, 90);
                        //特别需要注意角度旋转方向,如果角度旋转方向选错就形成闭环
                        graphicsPath.AddArc(new Rectangle(rec.X / 2, rec.Y + Width / 2, this.Width, this.Width), 0f, 90.0f);
                        break;
                    case PipeTurnDirection.Right:
                        rec = new Rectangle(0, Height - 2 * Width, 2 * Width, 2 * Width);
                        rec2 = new Rectangle(rec.X + (int)BorderWidth / 2, rec.Y + 1, rec.Width - (int)BorderWidth, rec.Height - (int)BorderWidth / 2);
                        PaintElliple(g, rec, rec2, 90, 90);
                        graphicsPath.AddArc(new Rectangle(Width / 2, rec.Y + Width / 2, Width, Width), 180, -90);
                        break;
                    case PipeTurnDirection.Up:
                    case PipeTurnDirection.Down:
                    case PipeTurnDirection.None:
                        PointF[] points = new PointF[] { new PointF(BorderWidth / 2, Height - Width), new PointF(BorderWidth / 2, Height), new PointF(Width - BorderWidth / 2, Height - Width), new PointF(Width - BorderWidth / 2, Height) };
                        PaintRectangle(g, new Rectangle(0, Height - Width, Width, Width), points, LinearGradientMode.Horizontal);
                        graphicsPath.AddLine(new PointF(Width / 2, Height - Width), new PointF(Width / 2, Height));
                        break;
                    default:
                        break;
                }
                if (Height > Width * 2)
                {
                    PointF[] points = new PointF[] { new PointF(BorderWidth / 2, Width), new PointF(BorderWidth / 2, Height - Width), new PointF(Width - BorderWidth / 2, Width), new PointF(Width - BorderWidth / 2, Height - Width) };
                    PaintRectangle(g, new Rectangle(0, Width, Width, Height - 2 * Width), points, LinearGradientMode.Horizontal);
                    // graphicsPath.AddLine(Height, Height / 2,Width- Height , Height / 2);
                }
            }
            if (IsActive)
            {
                //绘制流动条
                Pen barPen = new Pen(BarColor, BarHeight);
                barPen.DashStyle = DashStyle.Custom;
                barPen.DashOffset = startOffset;
                barPen.DashPattern = new float[] { BarLength, GapLength };
                graphicsPath.StartFigure();
                g.DrawPath(barPen, graphicsPath);
            }
        }
        //绘制椭圆与圆弧
        void PaintElliple(Graphics g, Rectangle rec, Rectangle recArc, float startAngle, float sweepAngle)
        {
            GraphicsPath graphicsPath = new GraphicsPath();
            graphicsPath.AddEllipse(rec);
            //画刷效果呈现由中心向四方层叠     
            PathGradientBrush brush = new PathGradientBrush(graphicsPath);
            brush.CenterPoint = new PointF(rec.X + rec.Width / 2, rec.Y + rec.Height / 2);
            brush.InterpolationColors = new ColorBlend() { Colors = new Color[] { PipeEdgeColor, PipeCenterColor, PipeEdgeColor }, Positions = new float[] { 0, 0.5f, 1 } };
            g.FillPie(brush, rec, startAngle, sweepAngle);
            g.DrawArc(new Pen(BorderColor, BorderWidth), recArc, startAngle, sweepAngle);
        }
        void PaintRectangle(Graphics g, Rectangle rec, PointF[] points, LinearGradientMode linearGradientMode = LinearGradientMode.Vertical)
        {
            //画刷效果呈现线型分布,注意与PathGradientBrush的区别
            LinearGradientBrush brush = new LinearGradientBrush(rec, PipeEdgeColor, PipeCenterColor, linearGradientMode);
            brush.InterpolationColors = new ColorBlend() { Colors = new Color[] { PipeEdgeColor, PipeCenterColor, PipeEdgeColor }, Positions = new float[] { 0, 0.5f, 1 } };
            brush.InterpolationColors = new ColorBlend() { Colors = new Color[] { PipeEdgeColor, PipeCenterColor, PipeEdgeColor }, Positions = new float[] { 0, 0.5f, 1 } };
            g.FillRectangle(brush, rec);
            g.DrawLine(new Pen(BorderColor, BorderWidth), points[0], points[1]);
            g.DrawLine(new Pen(BorderColor, BorderWidth), points[2], points[3]);
        }
    }
    /// <summary>
    /// 管道左、右的转向类型
    /// </summary>
    public enum PipeTurnDirection
    {
        Up = 1,
        Down,
        Left,
        Right,
        None
    }
    /// <summary>
    /// 管道的样式,水平还是数值
    /// </summary>
    public enum DirectionStyle
    {
        Horizontal = 1,
        Vertical
    }

7,使用Graphics绘制仪表盘1:

效果:
DashBoard控件代码
cs 复制代码
 [DefaultEvent("Click")]//指定默认事件
    public partial class DashBoard : UserControl
    {
        public DashBoard()
        {
            InitializeComponent();
            //  设置控件样式
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.SetStyle(ControlStyles.DoubleBuffer, true);
            this.SetStyle(ControlStyles.ResizeRedraw, true);
            this.SetStyle(ControlStyles.Selectable, true);
            this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            this.SetStyle(ControlStyles.UserPaint, true);
        }
        Font _wordFont = new Font("微软雅黑", 10, FontStyle.Bold);
        [Browsable(true), Category("自定义属性"), Description("文字字体")]
        public Font WordFont
        {
            get
            {
                return _wordFont;
            }
            set
            {
                _wordFont = value;
                this.Invalidate();
            }
        }
        Color _wordColor = Color.Black;
        /// <summary>
        /// 文字颜色
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("文字颜色")]
        public Color WordColor
        {
            get
            {
                return _wordColor;
            }
            set
            {
                _wordColor = value;
                this.Invalidate();
            }
        }
        bool _isWordShow = true;
        /// <summary>
        /// 文字是否显示
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("文字是否显示")]
        public bool IsWordShow
        {
            get
            {
                return _isWordShow;
            }
            set
            {
                _isWordShow = value;
                this.Invalidate();
            }
        }
        string _wordFormat = "实际温度:{0}℃";
        /// <summary>
        /// 文字是否显示的格式,例如:"实际温度:{0}℃",{0}为实际值的占位符
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("文字是否显示的格式,例如:'实际温度:{0}℃',{0}为实际值的占位符")]
        public string WordFormat
        {
            get
            {
                return _wordFormat;
            }
            set
            {
                _wordFormat = value;
                this.Invalidate();
            }
        }
        float _wordPositionFactor = 0.6f;
        /// <summary>
        /// 底部文字所在位置
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("底部文字所在位置")]
        public float WordPositionFactor
        {
            get
            {
                return _wordPositionFactor;
            }
            set
            {
                if (value < 0 || value > 1)
                {
                    _wordPositionFactor = 0.6f;
                }
                else
                {
                    _wordPositionFactor = value;
                }
                this.Invalidate();
            }
        }
        float _startValue = 0;
        /// <summary>
        /// 开始值
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("开始值")]
        public float StartValue
        {
            get
            {
                return _startValue;
            }
            set
            {
                _startValue = value;
                this.Invalidate();
            }
        }
        float _endValue = 160;
        /// <summary>
        /// 结束值
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("结束值")]
        public float EndValue
        {
            get
            {
                return _endValue;
            }
            set
            {
                _endValue = value;
                this.Invalidate();
            }
        }
        float _sweepRange = 240;
        /// <summary>
        /// 量程跨度,即从开始值到结束值所占用的角度
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("量程跨度,即从开始值到结束值所占用的角度")]
        public float SweepRange
        {
            get
            {
                return _sweepRange;
            }
            set
            {
                if (value < 0)
                {
                    _sweepRange = 240;
                }
                else
                {
                    _sweepRange = value;
                }
                this.Invalidate();
            }
        }
        int _largeMarkCount = 9;
        /// <summary>
        /// 刻度间隔值
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("刻度间隔值")]
        public int LargeMarkCount
        {
            get
            {
                return _largeMarkCount;
            }
            set
            {
                if (value < 0)
                {
                    _largeMarkCount = 9;
                }
                else
                {
                    _largeMarkCount = value;
                }
                this.Invalidate();
            }
        }
        MarkType _markStyle = MarkType.Average;
        /// <summary>
        /// 刻度分配样式,是平均分配还是自定义刻度值分配
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description(" 刻度分配样式,是平均分配还是自定义刻度值分配")]
        public MarkType MarkStyle
        {
            get
            {
                return _markStyle;
            }
            set
            {
                _largeMarkCount = 9;
                _markStyle = value;
                this.Invalidate();
            }
        }
        float[] _customMarkValue = { 0, 20, 40, 60, 80, 100, 120, 140, 160 };
        /// <summary>
        /// 自定义刻度值
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("自定义刻度值")]
        public float[] CustomMarkValue
        {
            get
            {
                return _customMarkValue;
            }
            set
            {
                _customMarkValue = value;
                this.Invalidate();
            }
        }
        Color _firstColor = Color.DodgerBlue;
        /// <summary>
        /// 第一部分颜色
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("第一部分颜色")]
        public Color FirstColor
        {
            get
            {
                return _firstColor;
            }
            set
            {
                _firstColor = value;
                this.Invalidate();
            }
        }
        int _firstColorHaveMarkCount = 6;
        /// <summary>
        /// 第一部分颜色所拥有的刻度数量
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("第一部分颜色所拥有的刻度数量")]
        public int FirstColorHaveMarkCount
        {
            get
            {
                return _firstColorHaveMarkCount;
            }
            set
            {
                if (value < 0)
                {
                    _firstColorHaveMarkCount = 2;
                }
                else
                {
                    _firstColorHaveMarkCount = value;
                }
                this.Invalidate();
            }
        }
        Color _secondColor = Color.LightGray;
        /// <summary>
        /// 第2部分颜色
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("第2部分颜色")]
        public Color SecondColor
        {
            get
            {
                return _secondColor;
            }
            set
            {
                _secondColor = value;
                this.Invalidate();
            }
        }
        int _outCircleWidth = 3;
        /// <summary>
        /// 外圆宽度
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("外圆宽度")]
        public int OutCircleWidth
        {
            get
            {
                return _outCircleWidth;
            }
            set
            {
                if (value < 0)
                {
                    return;
                }
                else
                {
                    _outCircleWidth = value;
                }
                this.Invalidate();
            }
        }
        float _pointerPartFactor = 0.1f;
        /// <summary>
        /// 指针部分所占的比例
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("指针部分所占的比例")]
        public float PointerPartFactor
        {
            get
            {
                return _pointerPartFactor;
            }
            set
            {
                if (value < 0 || value > 1)
                {
                    _pointerPartFactor = 0.2f;
                }
                else
                {
                    _pointerPartFactor = value;
                }
                this.Invalidate();
            }
        }
        /// <summary>
        /// 尺寸
        /// </summary>
        int Dimensions
        {
            get
            {
                if (Width < Height)
                {
                    return Width;
                }
                return Height;
            }
        }
        int _outCap = 5;
        /// <summary>
        /// 外间隙
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("外间隙")]
        public int OutGap
        {
            get
            {
                return _outCap;
            }
            set
            {
                if (value < 0)
                {
                    return;
                }
                _outCap = value;
                this.Invalidate();
            }
        }
        int _innerCap = 15;
        /// <summary>
        /// 内间隙
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("内间隙")]
        public int InnerGap
        {
            get
            {
                return _innerCap;
            }
            set
            {
                if (value < 0)
                {
                    return;
                }
                _innerCap = value;
                this.Invalidate();
            }
        }
        float _actualValue = 60;
        /// <summary>
        /// 实际值
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("实际值")]
        public float ActualValue
        {
            get
            {
                return _actualValue;
            }
            set
            {
                _actualValue = value;
                this.Invalidate();
            }
        }
        Color _markWordColor = Color.Black;
        [Browsable(true), Category("自定义属性"), Description("刻度文字颜色")]
        public Color MarkWordColor
        {
            get
            {
                return _markWordColor;
            }
            set
            {
                _markWordColor = value;
            }
        }
        Font _markWordFont = DefaultFont;
        [Browsable(true), Category("自定义属性"), Description("刻度文字字体")]
        public Font MarkWordFont
        {
            get
            {
                return _markWordFont;
            }
            set
            {
                _markWordFont = value;
                this.Invalidate();
            }
        }
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            Graphics g = e.Graphics;
            //计算需要绘制的刻度数量
            g.SmoothingMode = SmoothingMode.AntiAlias; //使绘图质量最高,即消除锯齿
            g.InterpolationMode = InterpolationMode.HighQualityBicubic;
            g.CompositingQuality = CompositingQuality.HighQuality;
            Dictionary<int, float> dic = new Dictionary<int, float>();
            if (MarkStyle == MarkType.Average)
            {
                for (int i = 0; i < LargeMarkCount; i++)
                {
                    dic.Add(i, i * (SweepRange / (LargeMarkCount - 1)));
                }
            }
            else
            {
                for (int i = 0; i < CustomMarkValue.Length; i++)
                {
                    dic.Add(i, (CustomMarkValue[i] - CustomMarkValue.Min()) / Math.Abs((CustomMarkValue.Max() - CustomMarkValue.Min())) * SweepRange);
                }
            }
            //绘制外圆
            if (FirstColorHaveMarkCount > dic.Count)
            {
                FirstColorHaveMarkCount = dic.Count;
            }
            float startAngle = (360 - SweepRange) / 2 + 90;
            //第1段
            g.DrawArc(new Pen(FirstColor, OutCircleWidth), OutGap, OutGap, Dimensions - OutGap * 2, Dimensions - OutGap * 2, startAngle, dic[FirstColorHaveMarkCount - 1]);
            //第2段
            g.DrawArc(new Pen(SecondColor, OutCircleWidth), OutGap, OutGap, Dimensions - OutGap * 2, Dimensions - OutGap * 2, dic[FirstColorHaveMarkCount - 1] + startAngle, dic[dic.Count - 1] - dic[FirstColorHaveMarkCount - 1]);
            //绘制刻度
            //偏移原点
            g.TranslateTransform(Dimensions / 2, Dimensions / 2);
            //旋转角度
            g.RotateTransform(-_sweepRange / 2);
            foreach (var key in dic.Keys)
            {
                RectangleF rec = new RectangleF(-2, -(Dimensions - 2 * OutGap) / 2 - OutGap, 4, OutGap * 2);
                if (key != 0)
                {
                    g.RotateTransform(dic[key] - dic[key - 1]);
                }
                if (key < FirstColorHaveMarkCount)
                {
                    g.FillRectangle(new SolidBrush(FirstColor), rec);
                }
                else
                {
                    g.FillRectangle(new SolidBrush(SecondColor), rec);
                }
            }
            //恢复坐标
            g.ResetTransform();
            //移动原点
            g.TranslateTransform(Dimensions / 2, Dimensions / 2);
            //旋转角度
            //  g.RotateTransform(-_sweepRange / 2);
            //绘制MarkWord
            //  PointF p = new PointF((float)(Dimensions * Math.Cos(230*1.0 / 180 * Math.PI)), (float)(Dimensions * Math.Sin(230*1.0 / 180 * Math.PI)));
            // g.DrawLine(Pens.Black, new PointF(0, 0), p);
            float largeInterval = SweepRange / (LargeMarkCount - 1);
            foreach (var key in dic.Keys)
            {
                //绘制文字
                string markWord;
                if (MarkStyle == MarkType.Average)
                {
                    markWord = Math.Round(StartValue + key * (EndValue - StartValue) / (LargeMarkCount - 1), 1).ToString();
                }
                else
                {
                    markWord = Math.Round(CustomMarkValue[key], 1).ToString();
                }
                float wordRadius = Dimensions / 2 - OutCircleWidth - OutGap - InnerGap;
                double x = wordRadius * Math.Cos((dic[key] + startAngle) / 180 * Math.PI);
                double y = wordRadius * Math.Sin((dic[key] + startAngle) / 180 * Math.PI);
                SizeF size = g.MeasureString(markWord, this.Font);
                PointF wordPoint = new PointF((float)x - size.Width / 2, (float)y - size.Height / 2);
                g.DrawString(markWord, MarkWordFont, new SolidBrush(MarkWordColor), wordPoint);
            }
            if (IsWordShow)
            {
                //绘制底部文字
                string txt = string.Format(WordFormat, ActualValue);
                SizeF wordSize = g.MeasureString(txt, WordFont);
                PointF txtPoint = new PointF(-wordSize.Width / 2, Dimensions / 2 * WordPositionFactor);
                g.DrawString(txt, WordFont, new SolidBrush(WordColor), txtPoint);
            }
            //绘制指针
            //圆心半径
            float circleRadius = Dimensions / 2 * this.PointerPartFactor;
            float pointerLength = circleRadius * 6;
            float trackWidth = pointerLength / 4;
            //绘制指针圆心
            g.FillEllipse(new SolidBrush(FirstColor), -circleRadius, -circleRadius, 2 * circleRadius, 2 * circleRadius);
            float relativeAngle;
            if (ActualValue > EndValue)
            {
                relativeAngle = SweepRange;
            }
            else if (ActualValue < StartValue)
            {
                relativeAngle = 0;
            }
            else
            {
                if (MarkStyle == MarkType.Average)
                {
                    relativeAngle = ((ActualValue - StartValue) / (EndValue - StartValue)) * SweepRange;
                }
                else
                {
                    if (CustomMarkValue.Length < 2)
                    {
                        CustomMarkValue = new float[] { 0, 20, 30 };
                    }
                    relativeAngle = (ActualValue - CustomMarkValue.Min()) / (CustomMarkValue.Max() - CustomMarkValue.Min()) * SweepRange;
                }
            }
            //绘制轨迹
            g.DrawArc(new Pen(FirstColor, trackWidth), -pointerLength + trackWidth / 2, -pointerLength + trackWidth / 2, 2 * pointerLength - trackWidth, 2 * pointerLength - trackWidth, startAngle, relativeAngle);
            //旋转角度
            g.RotateTransform(-_sweepRange / 2);
            //当前值对应的相对角度
            //绘制指针
            g.RotateTransform(relativeAngle);
            g.DrawLine(new Pen(FirstColor, 2), -1, 0, -1, -pointerLength);
        }
    }
    public enum MarkType
    {
        /// <summary>
        /// 平均分配刻度
        /// </summary>
        Average,
        /// <summary>
        /// 自定义刻度值分配
        /// </summary>
        Custom
    }
}

8,使用Graphics绘制仪表盘2:

效果:

Gague控件代码:
cs 复制代码
 [DefaultEvent("Click")]
    public partial class Gague : UserControl
    {
        public Gague()
        {
            InitializeComponent();
            //  设置控件样式
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.SetStyle(ControlStyles.DoubleBuffer, true);
            this.SetStyle(ControlStyles.ResizeRedraw, true);
            this.SetStyle(ControlStyles.Selectable, true);
            this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            this.SetStyle(ControlStyles.UserPaint, true);
        }
        Font _wordFont = new Font("微软雅黑", 10, FontStyle.Bold);
        [Browsable(true), Category("自定义属性"), Description("文字字体")]
        public Font WordFont
        {
            get
            {
                return _wordFont;
            }
            set
            {
                _wordFont = value;
                this.Invalidate();
            }
        }
        Color _wordColor = Color.SeaGreen;
        /// <summary>
        /// 文字颜色
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("文字颜色")]
        public Color WordColor
        {
            get
            {
                return _wordColor;
            }
            set
            {
                _wordColor = value;
                this.Invalidate();
            }
        }
        bool _isWordShow = true;
        /// <summary>
        /// 文字是否显示
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("文字是否显示")]
        public bool IsWordShow
        {
            get
            {
                return _isWordShow;
            }
            set
            {
                _isWordShow = value;
                this.Invalidate();
            }
        }
        string _wordFormat = "实际温度:{0}℃";
        /// <summary>
        /// 文字是否显示的格式,例如:"实际温度:{0}℃",{0}为实际值的占位符
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("文字是否显示的格式,例如:'实际温度:{0}℃',{0}为实际值的占位符")]
        public string WordFormat
        {
            get
            {
                return _wordFormat;
            }
            set
            {
                _wordFormat = value;
                this.Invalidate();
            }
        }
        float _wordPositionFactor = 0.7f;
        /// <summary>
        /// 底部文字所在位置
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("底部文字所在位置")]
        public float WordPositionFactor
        {
            get
            {
                return _wordPositionFactor;
            }
            set
            {
                if (value < 0 || value > 1)
                {
                    _wordPositionFactor = 0.6f;
                }
                else
                {
                    _wordPositionFactor = value;
                }
                this.Invalidate();
            }
        }
        float _startValue = 0;
        /// <summary>
        /// 开始值
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("开始值")]
        public float StartValue
        {
            get
            {
                return _startValue;
            }
            set
            {
                _startValue = value;
                this.Invalidate();
            }
        }
        float _endValue = 160;
        /// <summary>
        /// 结束值
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("结束值")]
        public float EndValue
        {
            get
            {
                return _endValue;
            }
            set
            {
                _endValue = value;
                this.Invalidate();
            }
        }
        float _lowAlarmValue = 25;
        /// <summary>
        /// 低报警阈值
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("低警戒值")]
        public float LowAlarmValue
        {
            get
            {
                return _lowAlarmValue;
            }
            set
            {
                if (value < StartValue)
                {
                    _lowAlarmValue = StartValue;
                }
                else
                {
                    _lowAlarmValue = value;
                }
                this.Invalidate();
            }
        }
        Color _lowAlarmColor = Color.Red;
        /// <summary>
        /// 低警区域颜色
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("低警区域颜色")]
        public Color LowAlarmColor
        {
            get
            {
                return _lowAlarmColor;
            }
            set
            {
                _lowAlarmColor = value;
                this.Invalidate();
            }
        }
        float _hightAlarmValue = 120;
        /// <summary>
        /// 高报警阈值
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("高警戒值")]
        public float HightAlarmValue
        {
            get
            {
                return _hightAlarmValue;
            }
            set
            {
                if (value > EndValue)
                {
                    _hightAlarmValue = EndValue;
                }
                else
                {
                    _hightAlarmValue = value;
                }
                this.Invalidate();
            }
        }
        Color _hightAlarmColor = Color.Red;
        /// <summary>
        /// 高报警区域颜色
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("高警区域颜色")]
        public Color HightAlarmColor
        {
            get
            {
                return _hightAlarmColor;
            }
            set
            {
                _hightAlarmColor = value;
                this.Invalidate();
            }
        }
        float _sweepRange = 240;
        /// <summary>
        /// 量程跨度,即从开始值到结束值所占用的角度
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("量程跨度,即从开始值到结束值所占用的角度")]
        public float SweepRange
        {
            get
            {
                return _sweepRange;
            }
            set
            {
                if (value < 0)
                {
                    _sweepRange = 240;
                }
                else
                {
                    _sweepRange = value;
                }
                this.Invalidate();
            }
        }
        Color _markColor = Color.LightSeaGreen;
        /// <summary>
        /// 刻度颜色
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("刻度颜色")]
        public Color MarkColor
        {
            get
            {
                return _markColor;
            }
            set
            {
                _markColor = value;
                this.Invalidate();
            }
        }
        Color _pointerColor = Color.Green;
        /// <summary>
        /// 指针颜色
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("指针颜色")]
        public Color PointerColor
        {
            get
            {
                return _pointerColor;
            }
            set
            {
                _pointerColor = value;
                this.Invalidate();
            }
        }
        float _pointerPartFactor = 0.8f;
        /// <summary>
        /// 指针部分所占的比例
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("指针部分所占的比例")]
        public float PointerPartFactor
        {
            get
            {
                return _pointerPartFactor;
            }
            set
            {
                if (value < 0 || value > 1)
                {
                    _pointerPartFactor = 0.2f;
                }
                else
                {
                    _pointerPartFactor = value;
                }
                this.Invalidate();
            }
        }
        /// <summary>
        /// 尺寸
        /// </summary>
        int Dimensions
        {
            get
            {
                if (Width < Height)
                {
                    return Width;
                }
                return Height;
            }
        }
        int _outCap = 5;
        /// <summary>
        /// 外间隙
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("外间隙")]
        public int OutGap
        {
            get
            {
                return _outCap;
            }
            set
            {
                if (value < 0)
                {
                    return;
                }
                _outCap = value;
                this.Invalidate();
            }
        }
        int _innerCap = 3;
        /// <summary>
        /// 内间隙
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("内间隙")]
        public int InnerGap
        {
            get
            {
                return _innerCap;
            }
            set
            {
                if (value < 0)
                {
                    return;
                }
                _innerCap = value;
                this.Invalidate();
            }
        }
        float _actualValue = 60;
        /// <summary>
        /// 实际值
        /// </summary>
        [Browsable(true), Category("自定义属性"), Description("实际值")]
        public float ActualValue
        {
            get
            {
                return _actualValue;
            }
            set
            {
                _actualValue = value;
                this.Invalidate();
            }
        }
        Color _markWordColor = Color.Black;
        [Browsable(true), Category("自定义属性"), Description("刻度文字颜色")]
        public Color MarkWordColor
        {
            get
            {
                return _markWordColor;
            }
            set
            {
                _markWordColor = value;
            }
        }
        Font _markWordFont = DefaultFont;
        [Browsable(true), Category("自定义属性"), Description("刻度文字颜色")]
        public Font MarkWordFont
        {
            get
            {
                return _markWordFont;
            }
            set
            {
                _markWordFont = value;
                this.Invalidate();
            }
        }
        int _largeMarkCount = 9;
        [Browsable(true), Category("自定义属性"), Description("大刻度数量")]
        public int LargeMarkCount
        {
            get
            {
                return _largeMarkCount;
            }
            set
            {
                if (value < 0)
                {
                    _largeMarkCount = 5;
                }
                else
                {
                    _largeMarkCount = value;
                }
                this.Invalidate();
            }
        }
        int _markWidth = 3;
        [Browsable(true), Category("自定义属性"), Description("刻度宽度")]
        public int MarkWidth
        {
            get
            {
                return _markWidth;
            }
            set
            {
                if (value < 0)
                {
                    _markWidth = 3;
                }
                else
                {
                    _markWidth = value;
                }
                this.Invalidate();
            }
        }
        int _markHeight = 4;
        [Browsable(true), Category("自定义属性"), Description("刻度宽度")]
        public int MarkHeight
        {
            get
            {
                return _markHeight;
            }
            set
            {
                if (value < 0)
                {
                    _markHeight = 4;
                }
                else
                {
                    _markHeight = value;
                }
                this.Invalidate();
            }
        }
        int _markWordGap = 24;
        [Browsable(true), Category("自定义属性"), Description("刻度文字与刻度间隙")]
        public int MarkWordGap
        {
            get
            {
                return _markWordGap;
            }
            set
            {
                if (value < 0)
                {
                    _markWordGap = 4;
                }
                else
                {
                    _markWordGap = value;
                }
                this.Invalidate();
            }
        }
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            Graphics g = e.Graphics;
            g.SmoothingMode = SmoothingMode.AntiAlias; //使绘图质量最高,即消除锯齿
            g.InterpolationMode = InterpolationMode.HighQualityBicubic;
            g.CompositingQuality = CompositingQuality.HighQuality;
            g.SmoothingMode = SmoothingMode.HighQuality;
            //绘制刻度
            //计算小刻度大小
            float smallMarkAngle = SweepRange / ((LargeMarkCount - 1) * 5);
            g.TranslateTransform(Dimensions / 2, Dimensions / 2);
            float offset = OutGap + InnerGap + MarkHeight;
            g.RotateTransform(-_sweepRange / 2);
            for (int i = 0; i <= LargeMarkCount - 1; i++)
            {
                //绘制大刻度
                PointF[] points = new PointF[]
                {
                        new PointF(-MarkWidth*1.0f/2, offset-Dimensions/2),
                        new PointF(MarkWidth*1.0f/2,offset-Dimensions/2),
                        new PointF(MarkWidth*1.0f/2,offset+MarkHeight*2-Dimensions/2),
                        new PointF(0,offset+MarkHeight*2+  MarkWidth*1.0f/2-Dimensions/2),
                        new PointF(-MarkWidth*1.0f/2,offset+MarkHeight*2-Dimensions/2)
                };
                g.FillPolygon(new SolidBrush(MarkColor), points);
                g.RotateTransform(smallMarkAngle);
                if (i != LargeMarkCount - 1)
                {
                    //绘制小刻度
                    for (int j = 0; j < 4; j++)
                    {
                        g.FillRectangle(new SolidBrush(MarkColor), -MarkWidth * 1.0f / 2, offset - Dimensions / 2, MarkWidth, MarkHeight);
                        g.RotateTransform(smallMarkAngle);
                    }
                }
            }
            //初始化原点,并将原点置于圆心
            g.ResetTransform();
            g.TranslateTransform(Dimensions / 2, Dimensions / 2);
            float startAngle = 180 - SweepRange / 2 + 90;
            float lowAlarmAngle;
            if (LowAlarmValue == StartValue)
            {
                lowAlarmAngle = 0;
            }
            else
            {
                lowAlarmAngle = (LowAlarmValue - StartValue) * 1.0f / (EndValue - StartValue) * SweepRange;
            }
            float hightAlarmAngle;
            if (HightAlarmValue == EndValue)
            {
                hightAlarmAngle = 0;
            }
            else
            {
                hightAlarmAngle = (EndValue - HightAlarmValue) * 1.0f / (EndValue - StartValue) * SweepRange;
            }
            //绘制警戒线
            Pen lowAlarmPen = new Pen(LowAlarmColor, MarkWidth)
            {
                DashStyle = DashStyle.Dash,
                DashPattern = new float[] { 3, 1 }
            };
            Pen hightAlarmPen = new Pen(HightAlarmColor, MarkWidth)
            {
                DashStyle = DashStyle.Dash,
                DashPattern = new float[] { 3, 1 }
            };
            g.DrawArc(lowAlarmPen, OutGap - Dimensions / 2, OutGap - Dimensions / 2, Dimensions - 2 * OutGap, Dimensions - 2 * OutGap, startAngle, lowAlarmAngle);
            g.DrawArc(hightAlarmPen, OutGap - Dimensions / 2, OutGap - Dimensions / 2, Dimensions - 2 * OutGap, Dimensions - 2 * OutGap, startAngle + SweepRange - hightAlarmAngle, hightAlarmAngle);
            //绘制刻度文字
            float largeMarkInterval = (EndValue - StartValue) / (LargeMarkCount - 1);
            for (int i = 0; i <= LargeMarkCount - 1; i++)
            {
                float angle = startAngle + i * 5 * smallMarkAngle;
                float radius = Dimensions / 2 - (OutGap + MarkWidth + InnerGap + MarkWordGap);
                PointF p = new PointF(radius * (float)(Math.Cos(angle / 180 * Math.PI)), radius * (float)(Math.Sin(angle / 180 * Math.PI)));
                string wordtxt = (Math.Round(StartValue + i * largeMarkInterval, 1)).ToString();
                SizeF wordSize = g.MeasureString(wordtxt, MarkWordFont);
                PointF wordPoint = new PointF(p.X - wordSize.Width / 2, p.Y - wordSize.Height / 2);
                g.DrawString(wordtxt, MarkWordFont, new SolidBrush(MarkWordColor), wordPoint);
                //  g.DrawLine(Pens.Black, new Point(0, 0), p);
            }
            //绘制文字
            if (this.IsWordShow)
            {
                string word = string.Format(WordFormat, ActualValue);
                SizeF wSize = g.MeasureString(word, WordFont);
                float wordPosition = Dimensions / 2 * this.WordPositionFactor;
                PointF wPoint = new PointF(-wSize.Width / 2, wordPosition - wSize.Height / 2);
                g.DrawString(word, WordFont, new SolidBrush(WordColor), wPoint);
            }
            //绘制指针
            //使指针置于0位
            g.RotateTransform(-SweepRange / 2);
            //计算旋转的角度
            if (StartValue != EndValue)
            {
                float pointerAngle;
                if (ActualValue < StartValue)
                {
                    pointerAngle = 0;
                }
                else if (ActualValue > EndValue)
                {
                    pointerAngle = SweepRange;
                }
                else
                {
                    pointerAngle = (ActualValue - StartValue) / (EndValue - StartValue) * SweepRange;
                }
                g.RotateTransform(pointerAngle);
            }
            float pointerLenght = Dimensions / 2 * PointerPartFactor;
            float centerRadius = pointerLenght / 30;
            GraphicsPath path = new GraphicsPath();
            path.AddArc(-centerRadius, -centerRadius, 2 * centerRadius, 2 * centerRadius, 0, 180);
            path.AddLine(-centerRadius, 0, 0, -pointerLenght);
            g.FillPath(new SolidBrush(PointerColor), path);
        }
    }
相关推荐
monkey_meng18 分钟前
【Rust中的迭代器】
开发语言·后端·rust
余衫马21 分钟前
Rust-Trait 特征编程
开发语言·后端·rust
monkey_meng24 分钟前
【Rust中多线程同步机制】
开发语言·redis·后端·rust
△曉風殘月〆4 小时前
WPF MVVM入门系列教程(二、依赖属性)
c#·wpf·mvvm
paopaokaka_luck5 小时前
【360】基于springboot的志愿服务管理系统
java·spring boot·后端·spring·毕业设计
逐·風6 小时前
unity关于自定义渲染、内存管理、性能调优、复杂物理模拟、并行计算以及插件开发
前端·unity·c#
码农小旋风6 小时前
详解K8S--声明式API
后端
Peter_chq6 小时前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
Yaml47 小时前
Spring Boot 与 Vue 共筑二手书籍交易卓越平台
java·spring boot·后端·mysql·spring·vue·二手书籍
小小小妮子~7 小时前
Spring Boot详解:从入门到精通
java·spring boot·后端