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

news2024/11/15 18:03:58

目录

1,使用Graphics绘制Toggle。

效果:

测试代码:

Toggle控件代码:

2,使用Graphics绘制Switch。

效果:

测试代码:

Switch控件代码:

3,使用Graphics绘制PanelHead。

效果

PanelHead控件代码:

4,自定义数字键盘NumberKeyBoard。

效果:

测试代码:

NumberKeyBoard控件代码

5,使用Graphics绘制LED。

效果:

LED控件代码:

6,使用Graphics绘制流动条。

效果:

FlowControl代码 :

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

效果:

DashBoard控件代码

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

效果:

Gague控件代码:


预览

1,使用Graphics绘制Toggle。

效果:

测试代码:
 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控件代码:
 [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。

效果:

测试代码:
 private void switchControl1_Click(object sender, EventArgs e)
        {
            switchControl1.SwitchStatus = !switchControl1.SwitchStatus;
        }
Switch控件代码:
 [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控件代码:
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。

效果:

测试代码:
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控件代码

 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控件代码:
  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代码 :
 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控件代码
 [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控件代码:
 [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);
        }
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2097196.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Nest 学习笔记】AOP切片编程

切片编程 AOP 把通用逻辑抽离出来&#xff0c;通过切面的方式添加到某个地方&#xff0c;可以复用和动态增删切面逻辑。 中间件 Middleware Middleware 中间件属于全局中间件&#xff08;Middleware 是 Express 的概念&#xff09; 常用于对请求接口进行日志记录 // main.ts …

七. 部署YOLOv8检测器-load-save-tensor

目录 前言0. 简述1. 案例运行2. 补充说明3. 代码分析3.1 main.cpp3.2 create_data.py 结语下载链接参考 前言 自动驾驶之心推出的 《CUDA与TensorRT部署实战课程》&#xff0c;链接。记录下个人学习笔记&#xff0c;仅供自己参考 本次课程我们来学习课程第六章—部署分类器&…

GMeLLo:结合知识图谱的 LLM 多跳问答技术,效果显著提升

1. GMeLLo 提出的背景 1.1 多跳问答 多跳问答的难度往往比较大&#xff0c;因为不仅要追溯事实&#xff0c;还要聚合与串联事实。 事实的来源可以是知识图谱、表格、自由格式文本&#xff0c;或者是这些来源的异构组合。 随着大型语言模型的发展&#xff0c;基于提示的方法…

安科瑞ACR10R网络电力仪表 CE认证 带外置互感器

产品概述&#xff1a; ‌‌安科瑞ACR10R网络电力仪表是一种集成了多种电力参数测量、电能计量、电能监测和考核管理等多种功能于一体的电力仪表。它适用于冶炼、钢铁、电焊、半导体等高能耗行业的节能改造工程&#xff0c;同时也适用于分布式光伏并网柜的功率监测、电力需求侧…

sqli-labs靶场通关攻略 56-60

主页有sqli-labs靶场通关攻略 1-55 第五六关 less-56 步骤一&#xff1a;闭合方式&#xff1a;?id1)-- 步骤二&#xff1a;查询数据库 ?id-1) union select 1,2,database() -- 步骤三&#xff1a;联合查询 查出网站的数据库表名 ?id-1) union select 1,2,group_concat(t…

探索AntSKPro AI知识库一体机:离线智能的便捷之选

在数字化时代&#xff0c;信息的获取和处理速度是企业和个人效率的关键。然而&#xff0c;网络连接的不稳定性常常成为阻碍。AntSKPro AI知识库一体机&#xff0c;一款专为离线环境设计的智能设备&#xff0c;以其卓越的性能和用户友好的设计&#xff0c;正在重新定义离线AI解决…

双指针--优选算法

个人主页&#xff1a;敲上瘾-CSDN博客 个人专栏&#xff1a;游戏、数据结构、c语言基础、c学习、OJ题 前言&#xff1a; 该篇文章我们主要来学习的是双指针算法&#xff0c;对于该类算法我们可以直接来做题&#xff0c;从题中去感知该算法的魅力&#xff0c;最后再从题中做总…

【数据结构】—— 线性表

目录 前言一、顺序表1.1 顺序表的定义及其特点1.2 顺序表的C语言实现1.2.1 定义顺序表1.2.2 初始化1.2.3 插入1.2.4 删除1.2.5 查找 二、链表2.1 链表的定义2.2 单向链表的实现2.2.1 定义单向链表2.2.2 创建链表2.2.3 插入元素2.2.4 删除元素2.2.5 查找 2.3 双向循环链表 前言 …

选刊风向标!985大学近十年发文热门IEEE期刊盘点

本期盘点同济大学近十年有关IEEE旗下发文较多的期刊&#xff0c;一起来看看哪些是双一流大学热门发文期刊&#xff1a; 1、IEEE Transactions on Cybernetics • 影响因子&#xff1a;9.4 • JCR1区&#xff0c;中科院1区-Top • 检索数据库&#xff1a;SCIE • 期刊分区&a…

stable diffusion的安装

stable diffusion的安装 一、前言二、安装python环境1、已经安装python环境&#xff0c;但非3.10.6版本&#xff08;可以不看&#xff09; 三、安装stable diffusion四、运行五、启动报错1、Torch is not able to use GPU2、Installing open_clip 卡住3、报错提示 "git&qu…

systemverilog中的DPI-C用例介绍

文章目录 前言一、dpi_longint二、dpi_packed_array三、dpi_structure四、相关参考总结 前言 本文主要基于VCS内置的三个关于DPI-C的使用用例&#xff0c;记录一下DPI-C的使用方法。测试用例的路径为$VCS_HOME/doc/examples/testbench/sv/。测试用例包括&#xff1a;dpi_longi…

自然语言处理:第四十三章 视觉RAG:变革传统深度学习模型开发流程,开创下一代多模态视觉模型的新时代

文章链接:微信公众平台 (qq.com) 写在前面: 笔者更新不易&#xff0c;希望走过路过点个关注和赞&#xff0c;笔芯!!! 写在前面: 笔者更新不易&#xff0c;希望走过路过点个关注和赞&#xff0c;笔芯!!! 写在前面: 笔者更新不易&#xff0c;希望走过路过点个关注和赞&#xff…

Chaper 09 深入理解Promise

文章目录 前言一、异步编程二、Promise 前言 在JavaScript中&#xff0c;异步编程是一个重要的概念。随着应用程序的复杂性增加&#xff0c;处理异步操作的方式也变得更加复杂。Promise是一种用于处理异步操作的对象&#xff0c;它提供了一种更清晰和更强大的方式来管理异步代…

智能的JavaScript开发工具WebStorm v2024.2全新发布

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具&#xff0c;被广大中国JS开发者誉为"Web前端开发神器""强大的HTML5编辑器""智能的JavaSscript IDE"等。与IntelliJ IDEA同源&#xff0c;继承了IntelliJ IDEA强大的JS部分的功能。 立即获…

学生防近视台灯什么品牌好?学生护眼台灯怎么选?收下这份攻略

根据中国报告大厅的数据&#xff0c;近年来&#xff0c;随着科技的不断进步&#xff0c;台灯行业亦得到了快速发展。早期的台灯主要采用白炽灯作为光源&#xff0c;但随着LED技术的日益成熟&#xff0c;LED台灯已成为市场主流。目前&#xff0c;台灯行业正处于高速发展阶段&…

【吊打面试官系列-Redis面试题】Redis 过期键的删除策略?

大家好&#xff0c;我是锋哥。今天分享关于 【Redis 过期键的删除策略】面试题&#xff0c;希望对大家有帮助&#xff1b; Redis 过期键的删除策略&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 1、定时删除:在设置键的过期时间的同时&#xff0c;创建…

19 - 路径搜索的综合

---- 整理自狄泰软件唐佐林老师课程 文章目录 1. 需求2. 一些工具3. 编译规则的依赖4. 实验 1. 需求 工程项目中不希望源码文件夹在编译时被改动&#xff08;只读文件夹&#xff09;在编译时自动创建文件夹&#xff08;build&#xff09;用于存放编译结果编译过程中能够自动搜…

java基本程序设计结构与数据类型

1.一个简单程序的编写、编译与运行 编写如下的Main.java public class Main{public static void main(String[] args){System.out.println("Hello World");} }上面的程序有几个要注意的点&#xff1a; ①public 是访问修饰符&#xff0c;用来表示其他程序对Main类的…

【C++】vector(下)--下篇

个人主页~ vector&#xff08;上&#xff09;~ vector&#xff08;下&#xff09;–上篇~ vector 二、模拟实现3、test.cpptest1test2test3test4test5test6 三、一个难题 二、模拟实现 3、test.cpp test1 这个没啥好说的&#xff0c;就是尾插和迭代器都能正常使用 //测尾…

中国各、省、市、县、乡镇基尼系数数据(2000-2023年)

基尼系数是一个国际上广泛用来综合考察居民内部收入分配差异状况的重要指标。它表示在全部居民收入中&#xff0c;用于进行不平均分配的那部分收入占总收入的百分比。基尼系数的值介于0和1之间&#xff0c;其中0代表收入分配绝对平均&#xff0c;即每个人的收入都相等&#xff…