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);
        }
    }
相关推荐
专注VB编程开发20年15 分钟前
C#全面超越JAVA,主要还是跨平台用的人少
java·c#·.net·跨平台
小信啊啊16 分钟前
Go语言切片slice
开发语言·后端·golang
Victor3562 小时前
Netty(20)如何实现基于Netty的WebSocket服务器?
后端
缘不易2 小时前
Springboot 整合JustAuth实现gitee授权登录
spring boot·后端·gitee
Kiri霧2 小时前
Range循环和切片
前端·后端·学习·golang
WizLC2 小时前
【Java】各种IO流知识详解
java·开发语言·后端·spring·intellij idea
Victor3562 小时前
Netty(19)Netty的性能优化手段有哪些?
后端
爬山算法2 小时前
Netty(15)Netty的线程模型是什么?它有哪些线程池类型?
java·后端
秋田君3 小时前
前端工程化部署入门:Windows + Nginx 实现多项目独立托管与跨域解决方案
前端·windows·nginx