(五十四)c#Winform自定义控件-仪表盘

前提

入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章。

官网:https://www.hzhcontrols.cn

GitHub:https://github.com/kwwwvagaa/NetWinformControl

码云:HZHControls控件库: HZHControls控件库,c#的winform自定义控件,对触屏具有更好的操作支持,项目是基于framework4.0,完全原生控件开发,没有使用任何第三方控件,你可以放心的用在你的项目中(winfromcontrol/winformcontrol/.net)。还有更丰富的工业控件持续增加中~~~

如果觉得写的还行,请点个 star 支持一下吧

欢迎前来交流探讨: 企鹅群568015492 企鹅群568015492

麻烦博客下方点个【推荐】,谢谢

NuGet

Install-Package HZH_Controls

目录

c#Winform自定义控件-目录_c#winform自定义控件-有图标的按钮-CSDN博客

用处及效果

准备工作

依然使用GDI+画的,不懂的话就百度一下吧

另外主要用到了三角函数,如果不懂,可以向初中的数学老师再问问(你也可以百度一下)

开始

添加一个类UCMeter 继承 UserControl

首先添加一个需要控制的属性

复制代码

  1 private int splitCount = 10;
  2         /// <summary>
  3         /// Gets or sets the split count.
  4         /// </summary>
  5         /// <value>The split count.</value>
  6         [Description("分隔刻度数量,>1"), Category("自定义")]
  7         public int SplitCount
  8         {
  9             get { return splitCount; }
 10             set
 11             {
 12                 if (value < 1)
 13                     return;
 14                 splitCount = value;
 15                 Refresh();
 16             }
 17         }
 18 
 19         private int meterDegrees = 150;
 20         /// <summary>
 21         /// Gets or sets the meter degrees.
 22         /// </summary>
 23         /// <value>The meter degrees.</value>
 24         [Description("表盘跨度角度,0-360"), Category("自定义")]
 25         public int MeterDegrees
 26         {
 27             get { return meterDegrees; }
 28             set
 29             {
 30                 if (value > 360 || value <= 0)
 31                     return;
 32                 meterDegrees = value;
 33                 Refresh();
 34             }
 35         }
 36 
 37         private decimal minValue = 0;
 38         /// <summary>
 39         /// Gets or sets the minimum value.
 40         /// </summary>
 41         /// <value>The minimum value.</value>
 42         [Description("最小值,<MaxValue"), Category("自定义")]
 43         public decimal MinValue
 44         {
 45             get { return minValue; }
 46             set
 47             {
 48                 if (value >= maxValue)
 49                     return;
 50                 minValue = value;
 51                 Refresh();
 52             }
 53         }
 54 
 55         private decimal maxValue = 100;
 56         /// <summary>
 57         /// Gets or sets the maximum value.
 58         /// </summary>
 59         /// <value>The maximum value.</value>
 60         [Description("最大值,>MinValue"), Category("自定义")]
 61         public decimal MaxValue
 62         {
 63             get { return maxValue; }
 64             set
 65             {
 66                 if (value <= minValue)
 67                     return;
 68                 maxValue = value;
 69                 Refresh();
 70             }
 71         }
 72         /// <summary>
 73         /// 获取或设置控件显示的文字的字体。
 74         /// </summary>
 75         /// <value>The font.</value>
 76         /// <PermissionSet>
 77         ///   <IPermission class="System.Security.Permissions.EnvironmentPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" />
 78         ///   <IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" />
 79         ///   <IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Flags="UnmanagedCode, ControlEvidence" />
 80         ///   <IPermission class="System.Diagnostics.PerformanceCounterPermission, System, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" />
 81         /// </PermissionSet>
 82         [Description("刻度字体"), Category("自定义")]
 83         public override Font Font
 84         {
 85             get
 86             {
 87                 return base.Font;
 88             }
 89             set
 90             {
 91                 base.Font = value;
 92                 Refresh();
 93             }
 94         }
 95 
 96         private decimal m_value = 0;
 97         /// <summary>
 98         /// Gets or sets the value.
 99         /// </summary>
100         /// <value>The value.</value>
101         [Description("值,>=MinValue并且<=MaxValue"), Category("自定义")]
102         public decimal Value
103         {
104             get { return m_value; }
105             set
106             {
107                 if (value < minValue || value > maxValue)
108                     return;
109                 m_value = value;
110                 Refresh();
111             }
112         }
113 
114         private MeterTextLocation textLocation = MeterTextLocation.None;
115         /// <summary>
116         /// Gets or sets the text location.
117         /// </summary>
118         /// <value>The text location.</value>
119         [Description("值和固定文字显示位置"), Category("自定义")]
120         public MeterTextLocation TextLocation
121         {
122             get { return textLocation; }
123             set
124             {
125                 textLocation = value;
126                 Refresh();
127             }
128         }
129 
130         private string fixedText;
131         /// <summary>
132         /// Gets or sets the fixed text.
133         /// </summary>
134         /// <value>The fixed text.</value>
135         [Description("固定文字"), Category("自定义")]
136         public string FixedText
137         {
138             get { return fixedText; }
139             set
140             {
141                 fixedText = value;
142                 Refresh();
143             }
144         }
145 
146         private Font textFont = DefaultFont;
147         /// <summary>
148         /// Gets or sets the text font.
149         /// </summary>
150         /// <value>The text font.</value>
151         [Description("值和固定文字字体"), Category("自定义")]
152         public Font TextFont
153         {
154             get { return textFont; }
155             set
156             {
157                 textFont = value;
158                 Refresh();
159             }
160         }
161 
162         private Color externalRoundColor = Color.FromArgb(255, 77, 59);
163         /// <summary>
164         /// Gets or sets the color of the external round.
165         /// </summary>
166         /// <value>The color of the external round.</value>
167         [Description("外圆颜色"), Category("自定义")]
168         public Color ExternalRoundColor
169         {
170             get { return externalRoundColor; }
171             set
172             {
173                 externalRoundColor = value;
174                 Refresh();
175             }
176         }
177 
178         private Color insideRoundColor = Color.FromArgb(255, 77, 59);
179         /// <summary>
180         /// Gets or sets the color of the inside round.
181         /// </summary>
182         /// <value>The color of the inside round.</value>
183         [Description("内圆颜色"), Category("自定义")]
184         public Color InsideRoundColor
185         {
186             get { return insideRoundColor; }
187             set
188             {
189                 insideRoundColor = value;
190                 Refresh();
191             }
192         }
193 
194         private Color boundaryLineColor = Color.FromArgb(255, 77, 59);
195         /// <summary>
196         /// Gets or sets the color of the boundary line.
197         /// </summary>
198         /// <value>The color of the boundary line.</value>
199         [Description("边界线颜色"), Category("自定义")]
200         public Color BoundaryLineColor
201         {
202             get { return boundaryLineColor; }
203             set
204             {
205                 boundaryLineColor = value;
206                 Refresh();
207             }
208         }
209 
210         private Color scaleColor = Color.FromArgb(255, 77, 59);
211         /// <summary>
212         /// Gets or sets the color of the scale.
213         /// </summary>
214         /// <value>The color of the scale.</value>
215         [Description("刻度颜色"), Category("自定义")]
216         public Color ScaleColor
217         {
218             get { return scaleColor; }
219             set
220             {
221                 scaleColor = value;
222                 Refresh();
223             }
224         }
225 
226         private Color scaleValueColor = Color.FromArgb(255, 77, 59);
227         /// <summary>
228         /// Gets or sets the color of the scale value.
229         /// </summary>
230         /// <value>The color of the scale value.</value>
231         [Description("刻度值文字颜色"), Category("自定义")]
232         public Color ScaleValueColor
233         {
234             get { return scaleValueColor; }
235             set
236             {
237                 scaleValueColor = value;
238                 Refresh();
239             }
240         }
241 
242         private Color pointerColor = Color.FromArgb(255, 77, 59);
243         /// <summary>
244         /// Gets or sets the color of the pointer.
245         /// </summary>
246         /// <value>The color of the pointer.</value>
247         [Description("指针颜色"), Category("自定义")]
248         public Color PointerColor
249         {
250             get { return pointerColor; }
251             set
252             {
253                 pointerColor = value;
254                 Refresh();
255             }
256         }
257 
258         private Color textColor = Color.FromArgb(255, 77, 59);
259         /// <summary>
260         /// Gets or sets the color of the text.
261         /// </summary>
262         /// <value>The color of the text.</value>
263         [Description("值和固定文字颜色"), Category("自定义")]
264         public Color TextColor
265         {
266             get { return textColor; }
267             set
268             {
269                 textColor = value;
270                 Refresh();
271             }
272         }
273 
274         Rectangle m_rectWorking;

复制代码

重绘

复制代码

 1  protected override void OnPaint(PaintEventArgs e)
 2         {
 3             base.OnPaint(e);
 4             var g = e.Graphics;
 5             g.SetGDIHigh();
 6 
 7             //外圆
 8             float fltStartAngle = -90 - (meterDegrees) / 2 + 360;
 9             var r1 = new Rectangle(m_rectWorking.Location, new Size(m_rectWorking.Width, m_rectWorking.Width));
10             g.DrawArc(new Pen(new SolidBrush(externalRoundColor), 1), r1, fltStartAngle, meterDegrees);
11             //内圆
12             var r2 = new Rectangle(m_rectWorking.Left + (m_rectWorking.Width - m_rectWorking.Width / 4) / 2, m_rectWorking.Top + (m_rectWorking.Width - m_rectWorking.Width / 4) / 2, m_rectWorking.Width / 4, m_rectWorking.Width / 4);
13             g.DrawArc(new Pen(new SolidBrush(insideRoundColor), 1), r2, fltStartAngle, meterDegrees);
14 
15             //边界线
16             if (meterDegrees != 360)
17             {
18                 float fltAngle = fltStartAngle - 180;
19 
20                 float intY = (float)(m_rectWorking.Top + m_rectWorking.Width / 2 - ((m_rectWorking.Width / 2 - m_rectWorking.Width / 8) * Math.Sin(Math.PI * (fltAngle / 180.00F))));
21                 float intX = (float)(m_rectWorking.Left + (m_rectWorking.Width / 2 - ((m_rectWorking.Width / 2 - m_rectWorking.Width / 8) * Math.Cos(Math.PI * (fltAngle / 180.00F)))));
22 
23                 float fltY1 = (float)(m_rectWorking.Top + m_rectWorking.Width / 2 - (m_rectWorking.Width / 8 * Math.Sin(Math.PI * (fltAngle / 180.00F))));
24                 float fltX1 = (float)(m_rectWorking.Left + (m_rectWorking.Width / 2 - (m_rectWorking.Width / 8 * Math.Cos(Math.PI * (fltAngle / 180.00F)))));
25 
26                 g.DrawLine(new Pen(new SolidBrush(boundaryLineColor), 1), new PointF(intX, intY), new PointF(fltX1, fltY1));
27                 g.DrawLine(new Pen(new SolidBrush(boundaryLineColor), 1), new PointF(m_rectWorking.Right - (fltX1 - m_rectWorking.Left), fltY1), new PointF(m_rectWorking.Right - (intX - m_rectWorking.Left), intY));
28             }
29 
30             //分割线
31             int _splitCount = splitCount * 2;
32             float fltSplitValue = (float)meterDegrees / (float)_splitCount;
33             for (int i = 0; i <= _splitCount; i++)
34             {
35                 float fltAngle = (fltStartAngle + fltSplitValue * i - 180) % 360;
36                 float fltY1 = (float)(m_rectWorking.Top + m_rectWorking.Width / 2 - ((m_rectWorking.Width / 2) * Math.Sin(Math.PI * (fltAngle / 180.00F))));
37                 float fltX1 = (float)(m_rectWorking.Left + (m_rectWorking.Width / 2 - ((m_rectWorking.Width / 2) * Math.Cos(Math.PI * (fltAngle / 180.00F)))));
38                 float fltY2 = 0;
39                 float fltX2 = 0;
40                 if (i % 2 == 0)
41                 {
42                     fltY2 = (float)(m_rectWorking.Top + m_rectWorking.Width / 2 - ((m_rectWorking.Width / 2 - 10) * Math.Sin(Math.PI * (fltAngle / 180.00F))));
43                     fltX2 = (float)(m_rectWorking.Left + (m_rectWorking.Width / 2 - ((m_rectWorking.Width / 2 - 10) * Math.Cos(Math.PI * (fltAngle / 180.00F)))));
44                     if (!(meterDegrees == 360 && i == _splitCount))
45                     {
46                         decimal decValue = minValue + (maxValue - minValue) / _splitCount * i;
47                         var txtSize = g.MeasureString(decValue.ToString("0.##"), this.Font);
48                         float fltFY1 = (float)(m_rectWorking.Top - txtSize.Height / 2 + m_rectWorking.Width / 2 - ((m_rectWorking.Width / 2 - 20) * Math.Sin(Math.PI * (fltAngle / 180.00F))));
49                         float fltFX1 = (float)(m_rectWorking.Left - txtSize.Width / 2 + (m_rectWorking.Width / 2 - ((m_rectWorking.Width / 2 - 20) * Math.Cos(Math.PI * (fltAngle / 180.00F)))));
50                         g.DrawString(decValue.ToString("0.##"), Font, new SolidBrush(scaleValueColor), fltFX1, fltFY1);
51                     }
52                 }
53                 else
54                 {
55                     fltY2 = (float)(m_rectWorking.Top + m_rectWorking.Width / 2 - ((m_rectWorking.Width / 2 - 5) * Math.Sin(Math.PI * (fltAngle / 180.00F))));
56                     fltX2 = (float)(m_rectWorking.Left + (m_rectWorking.Width / 2 - ((m_rectWorking.Width / 2 - 5) * Math.Cos(Math.PI * (fltAngle / 180.00F)))));
57                 }
58                 g.DrawLine(new Pen(new SolidBrush(scaleColor), i % 2 == 0 ? 2 : 1), new PointF(fltX1, fltY1), new PointF(fltX2, fltY2));
59             }
60 
61             //值文字和固定文字
62             if (textLocation != MeterTextLocation.None)
63             {
64                 string str = m_value.ToString("0.##");
65                 var txtSize = g.MeasureString(str, textFont);
66                 float fltY = m_rectWorking.Top + m_rectWorking.Width / 4 - txtSize.Height / 2;
67                 float fltX = m_rectWorking.Left + m_rectWorking.Width / 2 - txtSize.Width / 2;
68                 g.DrawString(str, textFont, new SolidBrush(textColor), new PointF(fltX, fltY));
69 
70                 if (!string.IsNullOrEmpty(fixedText))
71                 {
72                     str = fixedText;
73                     txtSize = g.MeasureString(str, textFont);
74                     fltY = m_rectWorking.Top + m_rectWorking.Width / 4 + txtSize.Height / 2;
75                     fltX = m_rectWorking.Left + m_rectWorking.Width / 2 - txtSize.Width / 2;
76                     g.DrawString(str, textFont, new SolidBrush(textColor), new PointF(fltX, fltY));
77                 }
78             }
79 
80             //画指针
81             g.FillEllipse(new SolidBrush(Color.FromArgb(100, pointerColor.R, pointerColor.G, pointerColor.B)), new Rectangle(m_rectWorking.Left + m_rectWorking.Width / 2 - 10, m_rectWorking.Top + m_rectWorking.Width / 2 - 10, 20, 20));
82             g.FillEllipse(Brushes.Red, new Rectangle(m_rectWorking.Left + m_rectWorking.Width / 2 - 5, m_rectWorking.Top + m_rectWorking.Width / 2 - 5, 10, 10));
83             float fltValueAngle = (fltStartAngle + ((float)(m_value - minValue) / (float)(maxValue - minValue)) * (float)meterDegrees - 180) % 360;
84             float intValueY1 = (float)(m_rectWorking.Top + m_rectWorking.Width / 2 - ((m_rectWorking.Width / 2 - 30) * Math.Sin(Math.PI * (fltValueAngle / 180.00F))));
85             float intValueX1 = (float)(m_rectWorking.Left + (m_rectWorking.Width / 2 - ((m_rectWorking.Width / 2 - 30) * Math.Cos(Math.PI * (fltValueAngle / 180.00F)))));
86             g.DrawLine(new Pen(new SolidBrush(pointerColor), 3), intValueX1, intValueY1, m_rectWorking.Left + m_rectWorking.Width / 2, m_rectWorking.Top + m_rectWorking.Width / 2);
87         }

复制代码

还有一个显示文字位置的枚举

复制代码

 1 /// <summary>
 2     /// Enum MeterTextLocation
 3     /// </summary>
 4     public enum MeterTextLocation
 5     {
 6         /// <summary>
 7         /// The none
 8         /// </summary>
 9         None,
10         /// <summary>
11         /// The top
12         /// </summary>
13         Top,
14         /// <summary>
15         /// The bottom
16         /// </summary>
17         Bottom
18     }

复制代码

代码就这么多了,看完整代码

// ***********************************************************************
// Assembly         : HZH_Controls
// Created          : 2019-09-03
//
// ***********************************************************************
// <copyright file="UCMeter.cs">
//     Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:623128629@qq.com
// </copyright>
//
// Blog: https://www.cnblogs.com/bfyx
// GitHub:https://github.com/kwwwvagaa/NetWinformControl
// gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git
//
// If you use this code, please keep this note.
// ***********************************************************************
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.ComponentModel;

namespace HZH_Controls.Controls
{
    /// <summary>
    /// Class UCMeter.
    /// Implements the <see cref="System.Windows.Forms.UserControl" />
    /// </summary>
    /// <seealso cref="System.Windows.Forms.UserControl" />
    public class UCMeter : UserControl
    {
        private int splitCount = 10;
        /// <summary>
        /// Gets or sets the split count.
        /// </summary>
        /// <value>The split count.</value>
        [Description("分隔刻度数量,>1"), Category("自定义")]
        public int SplitCount
        {
            get { return splitCount; }
            set
            {
                if (value < 1)
                    return;
                splitCount = value;
                Refresh();
            }
        }

        private int meterDegrees = 150;
        /// <summary>
        /// Gets or sets the meter degrees.
        /// </summary>
        /// <value>The meter degrees.</value>
        [Description("表盘跨度角度,0-360"), Category("自定义")]
        public int MeterDegrees
        {
            get { return meterDegrees; }
            set
            {
                if (value > 360 || value <= 0)
                    return;
                meterDegrees = value;
                Refresh();
            }
        }

        private decimal minValue = 0;
        /// <summary>
        /// Gets or sets the minimum value.
        /// </summary>
        /// <value>The minimum value.</value>
        [Description("最小值,<MaxValue"), Category("自定义")]
        public decimal MinValue
        {
            get { return minValue; }
            set
            {
                if (value >= maxValue)
                    return;
                minValue = value;
                Refresh();
            }
        }

        private decimal maxValue = 100;
        /// <summary>
        /// Gets or sets the maximum value.
        /// </summary>
        /// <value>The maximum value.</value>
        [Description("最大值,>MinValue"), Category("自定义")]
        public decimal MaxValue
        {
            get { return maxValue; }
            set
            {
                if (value <= minValue)
                    return;
                maxValue = value;
                Refresh();
            }
        }
        /// <summary>
        /// 获取或设置控件显示的文字的字体。
        /// </summary>
        /// <value>The font.</value>
        /// <PermissionSet>
        ///   <IPermission class="System.Security.Permissions.EnvironmentPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" />
        ///   <IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" />
        ///   <IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Flags="UnmanagedCode, ControlEvidence" />
        ///   <IPermission class="System.Diagnostics.PerformanceCounterPermission, System, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" />
        /// </PermissionSet>
        [Description("刻度字体"), Category("自定义")]
        public override Font Font
        {
            get
            {
                return base.Font;
            }
            set
            {
                base.Font = value;
                Refresh();
            }
        }

        private decimal m_value = 0;
        /// <summary>
        /// Gets or sets the value.
        /// </summary>
        /// <value>The value.</value>
        [Description("值,>=MinValue并且<=MaxValue"), Category("自定义")]
        public decimal Value
        {
            get { return m_value; }
            set
            {
                if (value < minValue || value > maxValue)
                    return;
                m_value = value;
                Refresh();
            }
        }

        private MeterTextLocation textLocation = MeterTextLocation.None;
        /// <summary>
        /// Gets or sets the text location.
        /// </summary>
        /// <value>The text location.</value>
        [Description("值和固定文字显示位置"), Category("自定义")]
        public MeterTextLocation TextLocation
        {
            get { return textLocation; }
            set
            {
                textLocation = value;
                Refresh();
            }
        }

        private string fixedText;
        /// <summary>
        /// Gets or sets the fixed text.
        /// </summary>
        /// <value>The fixed text.</value>
        [Description("固定文字"), Category("自定义")]
        public string FixedText
        {
            get { return fixedText; }
            set
            {
                fixedText = value;
                Refresh();
            }
        }

        private Font textFont = DefaultFont;
        /// <summary>
        /// Gets or sets the text font.
        /// </summary>
        /// <value>The text font.</value>
        [Description("值和固定文字字体"), Category("自定义")]
        public Font TextFont
        {
            get { return textFont; }
            set
            {
                textFont = value;
                Refresh();
            }
        }

        private Color externalRoundColor = Color.FromArgb(255, 77, 59);
        /// <summary>
        /// Gets or sets the color of the external round.
        /// </summary>
        /// <value>The color of the external round.</value>
        [Description("外圆颜色"), Category("自定义")]
        public Color ExternalRoundColor
        {
            get { return externalRoundColor; }
            set
            {
                externalRoundColor = value;
                Refresh();
            }
        }

        private Color insideRoundColor = Color.FromArgb(255, 77, 59);
        /// <summary>
        /// Gets or sets the color of the inside round.
        /// </summary>
        /// <value>The color of the inside round.</value>
        [Description("内圆颜色"), Category("自定义")]
        public Color InsideRoundColor
        {
            get { return insideRoundColor; }
            set
            {
                insideRoundColor = value;
                Refresh();
            }
        }

        private Color boundaryLineColor = Color.FromArgb(255, 77, 59);
        /// <summary>
        /// Gets or sets the color of the boundary line.
        /// </summary>
        /// <value>The color of the boundary line.</value>
        [Description("边界线颜色"), Category("自定义")]
        public Color BoundaryLineColor
        {
            get { return boundaryLineColor; }
            set
            {
                boundaryLineColor = value;
                Refresh();
            }
        }

        private Color scaleColor = Color.FromArgb(255, 77, 59);
        /// <summary>
        /// Gets or sets the color of the scale.
        /// </summary>
        /// <value>The color of the scale.</value>
        [Description("刻度颜色"), Category("自定义")]
        public Color ScaleColor
        {
            get { return scaleColor; }
            set
            {
                scaleColor = value;
                Refresh();
            }
        }

        private Color scaleValueColor = Color.FromArgb(255, 77, 59);
        /// <summary>
        /// Gets or sets the color of the scale value.
        /// </summary>
        /// <value>The color of the scale value.</value>
        [Description("刻度值文字颜色"), Category("自定义")]
        public Color ScaleValueColor
        {
            get { return scaleValueColor; }
            set
            {
                scaleValueColor = value;
                Refresh();
            }
        }

        private Color pointerColor = Color.FromArgb(255, 77, 59);
        /// <summary>
        /// Gets or sets the color of the pointer.
        /// </summary>
        /// <value>The color of the pointer.</value>
        [Description("指针颜色"), Category("自定义")]
        public Color PointerColor
        {
            get { return pointerColor; }
            set
            {
                pointerColor = value;
                Refresh();
            }
        }

        private Color textColor = Color.FromArgb(255, 77, 59);
        /// <summary>
        /// Gets or sets the color of the text.
        /// </summary>
        /// <value>The color of the text.</value>
        [Description("值和固定文字颜色"), Category("自定义")]
        public Color TextColor
        {
            get { return textColor; }
            set
            {
                textColor = value;
                Refresh();
            }
        }

        Rectangle m_rectWorking;
        public UCMeter()
        {
            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);
            this.SizeChanged += UCMeter1_SizeChanged;
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
            this.Size = new Size(350, 200);
        }

        void UCMeter1_SizeChanged(object sender, EventArgs e)
        {
            m_rectWorking = new Rectangle(10, 10, this.Width - 20, this.Height - 20);
        }


        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            var g = e.Graphics;
            g.SetGDIHigh();

            //外圆
            float fltStartAngle = -90 - (meterDegrees) / 2 + 360;
            var r1 = new Rectangle(m_rectWorking.Location, new Size(m_rectWorking.Width, m_rectWorking.Width));
            g.DrawArc(new Pen(new SolidBrush(externalRoundColor), 1), r1, fltStartAngle, meterDegrees);
            //内圆
            var r2 = new Rectangle(m_rectWorking.Left + (m_rectWorking.Width - m_rectWorking.Width / 4) / 2, m_rectWorking.Top + (m_rectWorking.Width - m_rectWorking.Width / 4) / 2, m_rectWorking.Width / 4, m_rectWorking.Width / 4);
            g.DrawArc(new Pen(new SolidBrush(insideRoundColor), 1), r2, fltStartAngle, meterDegrees);

            //边界线
            if (meterDegrees != 360)
            {
                float fltAngle = fltStartAngle - 180;

                float intY = (float)(m_rectWorking.Top + m_rectWorking.Width / 2 - ((m_rectWorking.Width / 2 - m_rectWorking.Width / 8) * Math.Sin(Math.PI * (fltAngle / 180.00F))));
                float intX = (float)(m_rectWorking.Left + (m_rectWorking.Width / 2 - ((m_rectWorking.Width / 2 - m_rectWorking.Width / 8) * Math.Cos(Math.PI * (fltAngle / 180.00F)))));

                float fltY1 = (float)(m_rectWorking.Top + m_rectWorking.Width / 2 - (m_rectWorking.Width / 8 * Math.Sin(Math.PI * (fltAngle / 180.00F))));
                float fltX1 = (float)(m_rectWorking.Left + (m_rectWorking.Width / 2 - (m_rectWorking.Width / 8 * Math.Cos(Math.PI * (fltAngle / 180.00F)))));

                g.DrawLine(new Pen(new SolidBrush(boundaryLineColor), 1), new PointF(intX, intY), new PointF(fltX1, fltY1));
                g.DrawLine(new Pen(new SolidBrush(boundaryLineColor), 1), new PointF(m_rectWorking.Right - (fltX1 - m_rectWorking.Left), fltY1), new PointF(m_rectWorking.Right - (intX - m_rectWorking.Left), intY));
            }

            //分割线
            int _splitCount = splitCount * 2;
            float fltSplitValue = (float)meterDegrees / (float)_splitCount;
            for (int i = 0; i <= _splitCount; i++)
            {
                float fltAngle = (fltStartAngle + fltSplitValue * i - 180) % 360;
                float fltY1 = (float)(m_rectWorking.Top + m_rectWorking.Width / 2 - ((m_rectWorking.Width / 2) * Math.Sin(Math.PI * (fltAngle / 180.00F))));
                float fltX1 = (float)(m_rectWorking.Left + (m_rectWorking.Width / 2 - ((m_rectWorking.Width / 2) * Math.Cos(Math.PI * (fltAngle / 180.00F)))));
                float fltY2 = 0;
                float fltX2 = 0;
                if (i % 2 == 0)
                {
                    fltY2 = (float)(m_rectWorking.Top + m_rectWorking.Width / 2 - ((m_rectWorking.Width / 2 - 10) * Math.Sin(Math.PI * (fltAngle / 180.00F))));
                    fltX2 = (float)(m_rectWorking.Left + (m_rectWorking.Width / 2 - ((m_rectWorking.Width / 2 - 10) * Math.Cos(Math.PI * (fltAngle / 180.00F)))));
                    if (!(meterDegrees == 360 && i == _splitCount))
                    {
                        decimal decValue = minValue + (maxValue - minValue) / _splitCount * i;
                        var txtSize = g.MeasureString(decValue.ToString("0.##"), this.Font);
                        float fltFY1 = (float)(m_rectWorking.Top - txtSize.Height / 2 + m_rectWorking.Width / 2 - ((m_rectWorking.Width / 2 - 20) * Math.Sin(Math.PI * (fltAngle / 180.00F))));
                        float fltFX1 = (float)(m_rectWorking.Left - txtSize.Width / 2 + (m_rectWorking.Width / 2 - ((m_rectWorking.Width / 2 - 20) * Math.Cos(Math.PI * (fltAngle / 180.00F)))));
                        g.DrawString(decValue.ToString("0.##"), Font, new SolidBrush(scaleValueColor), fltFX1, fltFY1);
                    }
                }
                else
                {
                    fltY2 = (float)(m_rectWorking.Top + m_rectWorking.Width / 2 - ((m_rectWorking.Width / 2 - 5) * Math.Sin(Math.PI * (fltAngle / 180.00F))));
                    fltX2 = (float)(m_rectWorking.Left + (m_rectWorking.Width / 2 - ((m_rectWorking.Width / 2 - 5) * Math.Cos(Math.PI * (fltAngle / 180.00F)))));
                }
                g.DrawLine(new Pen(new SolidBrush(scaleColor), i % 2 == 0 ? 2 : 1), new PointF(fltX1, fltY1), new PointF(fltX2, fltY2));
            }

            //值文字和固定文字
            if (textLocation != MeterTextLocation.None)
            {
                string str = m_value.ToString("0.##");
                var txtSize = g.MeasureString(str, textFont);
                float fltY = m_rectWorking.Top + m_rectWorking.Width / 4 - txtSize.Height / 2;
                float fltX = m_rectWorking.Left + m_rectWorking.Width / 2 - txtSize.Width / 2;
                g.DrawString(str, textFont, new SolidBrush(textColor), new PointF(fltX, fltY));

                if (!string.IsNullOrEmpty(fixedText))
                {
                    str = fixedText;
                    txtSize = g.MeasureString(str, textFont);
                    fltY = m_rectWorking.Top + m_rectWorking.Width / 4 + txtSize.Height / 2;
                    fltX = m_rectWorking.Left + m_rectWorking.Width / 2 - txtSize.Width / 2;
                    g.DrawString(str, textFont, new SolidBrush(textColor), new PointF(fltX, fltY));
                }
            }

            //画指针
            g.FillEllipse(new SolidBrush(Color.FromArgb(100, pointerColor.R, pointerColor.G, pointerColor.B)), new Rectangle(m_rectWorking.Left + m_rectWorking.Width / 2 - 10, m_rectWorking.Top + m_rectWorking.Width / 2 - 10, 20, 20));
            g.FillEllipse(Brushes.Red, new Rectangle(m_rectWorking.Left + m_rectWorking.Width / 2 - 5, m_rectWorking.Top + m_rectWorking.Width / 2 - 5, 10, 10));
            float fltValueAngle = (fltStartAngle + ((float)(m_value - minValue) / (float)(maxValue - minValue)) * (float)meterDegrees - 180) % 360;
            float intValueY1 = (float)(m_rectWorking.Top + m_rectWorking.Width / 2 - ((m_rectWorking.Width / 2 - 30) * Math.Sin(Math.PI * (fltValueAngle / 180.00F))));
            float intValueX1 = (float)(m_rectWorking.Left + (m_rectWorking.Width / 2 - ((m_rectWorking.Width / 2 - 30) * Math.Cos(Math.PI * (fltValueAngle / 180.00F)))));
            g.DrawLine(new Pen(new SolidBrush(pointerColor), 3), intValueX1, intValueY1, m_rectWorking.Left + m_rectWorking.Width / 2, m_rectWorking.Top + m_rectWorking.Width / 2);
        }
    }

    /// <summary>
    /// Enum MeterTextLocation
    /// </summary>
    public enum MeterTextLocation
    {
        /// <summary>
        /// The none
        /// </summary>
        None,
        /// <summary>
        /// The top
        /// </summary>
        Top,
        /// <summary>
        /// The bottom
        /// </summary>
        Bottom
    }
}

最后的话

如果你喜欢的话,请到 HZHControls控件库: HZHControls控件库,c#的winform自定义控件,对触屏具有更好的操作支持,项目是基于framework4.0,完全原生控件开发,没有使用任何第三方控件,你可以放心的用在你的项目中(winfromcontrol/winformcontrol/.net)。还有更丰富的工业控件持续增加中~~~ 点个星星吧

评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值