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

前提

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

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

码云:https://gitee.com/kwwwvagaa/net_winform_custom_control.git

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

NuGet

Install-Package HZH_Controls

目录

https://www.cnblogs.com/bfyx/p/11364884.html

用处及效果

准备工作

依然使用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     }

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

  1 // ***********************************************************************
  2 // Assembly         : HZH_Controls
  3 // Created          : 2019-09-03
  4 //
  5 // ***********************************************************************
  6 // <copyright file="UCMeter.cs">
  7 //     Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:623128629@qq.com
  8 // </copyright>
  9 //
 10 // Blog: https://www.cnblogs.com/bfyx
 11 // GitHub:https://github.com/kwwwvagaa/NetWinformControl
 12 // gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git
 13 //
 14 // If you use this code, please keep this note.
 15 // ***********************************************************************
 16 using System;
 17 using System.Collections.Generic;
 18 using System.Linq;
 19 using System.Text;
 20 using System.Windows.Forms;
 21 using System.Drawing;
 22 using System.Drawing.Drawing2D;
 23 using System.ComponentModel;
 24 
 25 namespace HZH_Controls.Controls
 26 {
 27     /// <summary>
 28     /// Class UCMeter.
 29     /// Implements the <see cref="System.Windows.Forms.UserControl" />
 30     /// </summary>
 31     /// <seealso cref="System.Windows.Forms.UserControl" />
 32     public class UCMeter : UserControl
 33     {
 34         private int splitCount = 10;
 35         /// <summary>
 36         /// Gets or sets the split count.
 37         /// </summary>
 38         /// <value>The split count.</value>
 39         [Description("分隔刻度数量,>1"), Category("自定义")]
 40         public int SplitCount
 41         {
 42             get { return splitCount; }
 43             set
 44             {
 45                 if (value < 1)
 46                     return;
 47                 splitCount = value;
 48                 Refresh();
 49             }
 50         }
 51 
 52         private int meterDegrees = 150;
 53         /// <summary>
 54         /// Gets or sets the meter degrees.
 55         /// </summary>
 56         /// <value>The meter degrees.</value>
 57         [Description("表盘跨度角度,0-360"), Category("自定义")]
 58         public int MeterDegrees
 59         {
 60             get { return meterDegrees; }
 61             set
 62             {
 63                 if (value > 360 || value <= 0)
 64                     return;
 65                 meterDegrees = value;
 66                 Refresh();
 67             }
 68         }
 69 
 70         private decimal minValue = 0;
 71         /// <summary>
 72         /// Gets or sets the minimum value.
 73         /// </summary>
 74         /// <value>The minimum value.</value>
 75         [Description("最小值,<MaxValue"), Category("自定义")]
 76         public decimal MinValue
 77         {
 78             get { return minValue; }
 79             set
 80             {
 81                 if (value >= maxValue)
 82                     return;
 83                 minValue = value;
 84                 Refresh();
 85             }
 86         }
 87 
 88         private decimal maxValue = 100;
 89         /// <summary>
 90         /// Gets or sets the maximum value.
 91         /// </summary>
 92         /// <value>The maximum value.</value>
 93         [Description("最大值,>MinValue"), Category("自定义")]
 94         public decimal MaxValue
 95         {
 96             get { return maxValue; }
 97             set
 98             {
 99                 if (value <= minValue)
100                     return;
101                 maxValue = value;
102                 Refresh();
103             }
104         }
105         /// <summary>
106         /// 获取或设置控件显示的文字的字体。
107         /// </summary>
108         /// <value>The font.</value>
109         /// <PermissionSet>
110         ///   <IPermission class="System.Security.Permissions.EnvironmentPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" />
111         ///   <IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" />
112         ///   <IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Flags="UnmanagedCode, ControlEvidence" />
113         ///   <IPermission class="System.Diagnostics.PerformanceCounterPermission, System, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" />
114         /// </PermissionSet>
115         [Description("刻度字体"), Category("自定义")]
116         public override Font Font
117         {
118             get
119             {
120                 return base.Font;
121             }
122             set
123             {
124                 base.Font = value;
125                 Refresh();
126             }
127         }
128 
129         private decimal m_value = 0;
130         /// <summary>
131         /// Gets or sets the value.
132         /// </summary>
133         /// <value>The value.</value>
134         [Description("值,>=MinValue并且<=MaxValue"), Category("自定义")]
135         public decimal Value
136         {
137             get { return m_value; }
138             set
139             {
140                 if (value < minValue || value > maxValue)
141                     return;
142                 m_value = value;
143                 Refresh();
144             }
145         }
146 
147         private MeterTextLocation textLocation = MeterTextLocation.None;
148         /// <summary>
149         /// Gets or sets the text location.
150         /// </summary>
151         /// <value>The text location.</value>
152         [Description("值和固定文字显示位置"), Category("自定义")]
153         public MeterTextLocation TextLocation
154         {
155             get { return textLocation; }
156             set
157             {
158                 textLocation = value;
159                 Refresh();
160             }
161         }
162 
163         private string fixedText;
164         /// <summary>
165         /// Gets or sets the fixed text.
166         /// </summary>
167         /// <value>The fixed text.</value>
168         [Description("固定文字"), Category("自定义")]
169         public string FixedText
170         {
171             get { return fixedText; }
172             set
173             {
174                 fixedText = value;
175                 Refresh();
176             }
177         }
178 
179         private Font textFont = DefaultFont;
180         /// <summary>
181         /// Gets or sets the text font.
182         /// </summary>
183         /// <value>The text font.</value>
184         [Description("值和固定文字字体"), Category("自定义")]
185         public Font TextFont
186         {
187             get { return textFont; }
188             set
189             {
190                 textFont = value;
191                 Refresh();
192             }
193         }
194 
195         private Color externalRoundColor = Color.FromArgb(255, 77, 59);
196         /// <summary>
197         /// Gets or sets the color of the external round.
198         /// </summary>
199         /// <value>The color of the external round.</value>
200         [Description("外圆颜色"), Category("自定义")]
201         public Color ExternalRoundColor
202         {
203             get { return externalRoundColor; }
204             set
205             {
206                 externalRoundColor = value;
207                 Refresh();
208             }
209         }
210 
211         private Color insideRoundColor = Color.FromArgb(255, 77, 59);
212         /// <summary>
213         /// Gets or sets the color of the inside round.
214         /// </summary>
215         /// <value>The color of the inside round.</value>
216         [Description("内圆颜色"), Category("自定义")]
217         public Color InsideRoundColor
218         {
219             get { return insideRoundColor; }
220             set
221             {
222                 insideRoundColor = value;
223                 Refresh();
224             }
225         }
226 
227         private Color boundaryLineColor = Color.FromArgb(255, 77, 59);
228         /// <summary>
229         /// Gets or sets the color of the boundary line.
230         /// </summary>
231         /// <value>The color of the boundary line.</value>
232         [Description("边界线颜色"), Category("自定义")]
233         public Color BoundaryLineColor
234         {
235             get { return boundaryLineColor; }
236             set
237             {
238                 boundaryLineColor = value;
239                 Refresh();
240             }
241         }
242 
243         private Color scaleColor = Color.FromArgb(255, 77, 59);
244         /// <summary>
245         /// Gets or sets the color of the scale.
246         /// </summary>
247         /// <value>The color of the scale.</value>
248         [Description("刻度颜色"), Category("自定义")]
249         public Color ScaleColor
250         {
251             get { return scaleColor; }
252             set
253             {
254                 scaleColor = value;
255                 Refresh();
256             }
257         }
258 
259         private Color scaleValueColor = Color.FromArgb(255, 77, 59);
260         /// <summary>
261         /// Gets or sets the color of the scale value.
262         /// </summary>
263         /// <value>The color of the scale value.</value>
264         [Description("刻度值文字颜色"), Category("自定义")]
265         public Color ScaleValueColor
266         {
267             get { return scaleValueColor; }
268             set
269             {
270                 scaleValueColor = value;
271                 Refresh();
272             }
273         }
274 
275         private Color pointerColor = Color.FromArgb(255, 77, 59);
276         /// <summary>
277         /// Gets or sets the color of the pointer.
278         /// </summary>
279         /// <value>The color of the pointer.</value>
280         [Description("指针颜色"), Category("自定义")]
281         public Color PointerColor
282         {
283             get { return pointerColor; }
284             set
285             {
286                 pointerColor = value;
287                 Refresh();
288             }
289         }
290 
291         private Color textColor = Color.FromArgb(255, 77, 59);
292         /// <summary>
293         /// Gets or sets the color of the text.
294         /// </summary>
295         /// <value>The color of the text.</value>
296         [Description("值和固定文字颜色"), Category("自定义")]
297         public Color TextColor
298         {
299             get { return textColor; }
300             set
301             {
302                 textColor = value;
303                 Refresh();
304             }
305         }
306 
307         Rectangle m_rectWorking;
308         public UCMeter()
309         {
310             this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
311             this.SetStyle(ControlStyles.DoubleBuffer, true);
312             this.SetStyle(ControlStyles.ResizeRedraw, true);
313             this.SetStyle(ControlStyles.Selectable, true);
314             this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
315             this.SetStyle(ControlStyles.UserPaint, true);
316             this.SizeChanged += UCMeter1_SizeChanged;
317             this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
318             this.Size = new Size(350, 200);
319         }
320 
321         void UCMeter1_SizeChanged(object sender, EventArgs e)
322         {
323             m_rectWorking = new Rectangle(10, 10, this.Width - 20, this.Height - 20);
324         }
325 
326 
327         protected override void OnPaint(PaintEventArgs e)
328         {
329             base.OnPaint(e);
330             var g = e.Graphics;
331             g.SetGDIHigh();
332 
333             //外圆
334             float fltStartAngle = -90 - (meterDegrees) / 2 + 360;
335             var r1 = new Rectangle(m_rectWorking.Location, new Size(m_rectWorking.Width, m_rectWorking.Width));
336             g.DrawArc(new Pen(new SolidBrush(externalRoundColor), 1), r1, fltStartAngle, meterDegrees);
337             //内圆
338             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);
339             g.DrawArc(new Pen(new SolidBrush(insideRoundColor), 1), r2, fltStartAngle, meterDegrees);
340 
341             //边界线
342             if (meterDegrees != 360)
343             {
344                 float fltAngle = fltStartAngle - 180;
345 
346                 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))));
347                 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)))));
348 
349                 float fltY1 = (float)(m_rectWorking.Top + m_rectWorking.Width / 2 - (m_rectWorking.Width / 8 * Math.Sin(Math.PI * (fltAngle / 180.00F))));
350                 float fltX1 = (float)(m_rectWorking.Left + (m_rectWorking.Width / 2 - (m_rectWorking.Width / 8 * Math.Cos(Math.PI * (fltAngle / 180.00F)))));
351 
352                 g.DrawLine(new Pen(new SolidBrush(boundaryLineColor), 1), new PointF(intX, intY), new PointF(fltX1, fltY1));
353                 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));
354             }
355 
356             //分割线
357             int _splitCount = splitCount * 2;
358             float fltSplitValue = (float)meterDegrees / (float)_splitCount;
359             for (int i = 0; i <= _splitCount; i++)
360             {
361                 float fltAngle = (fltStartAngle + fltSplitValue * i - 180) % 360;
362                 float fltY1 = (float)(m_rectWorking.Top + m_rectWorking.Width / 2 - ((m_rectWorking.Width / 2) * Math.Sin(Math.PI * (fltAngle / 180.00F))));
363                 float fltX1 = (float)(m_rectWorking.Left + (m_rectWorking.Width / 2 - ((m_rectWorking.Width / 2) * Math.Cos(Math.PI * (fltAngle / 180.00F)))));
364                 float fltY2 = 0;
365                 float fltX2 = 0;
366                 if (i % 2 == 0)
367                 {
368                     fltY2 = (float)(m_rectWorking.Top + m_rectWorking.Width / 2 - ((m_rectWorking.Width / 2 - 10) * Math.Sin(Math.PI * (fltAngle / 180.00F))));
369                     fltX2 = (float)(m_rectWorking.Left + (m_rectWorking.Width / 2 - ((m_rectWorking.Width / 2 - 10) * Math.Cos(Math.PI * (fltAngle / 180.00F)))));
370                     if (!(meterDegrees == 360 && i == _splitCount))
371                     {
372                         decimal decValue = minValue + (maxValue - minValue) / _splitCount * i;
373                         var txtSize = g.MeasureString(decValue.ToString("0.##"), this.Font);
374                         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))));
375                         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)))));
376                         g.DrawString(decValue.ToString("0.##"), Font, new SolidBrush(scaleValueColor), fltFX1, fltFY1);
377                     }
378                 }
379                 else
380                 {
381                     fltY2 = (float)(m_rectWorking.Top + m_rectWorking.Width / 2 - ((m_rectWorking.Width / 2 - 5) * Math.Sin(Math.PI * (fltAngle / 180.00F))));
382                     fltX2 = (float)(m_rectWorking.Left + (m_rectWorking.Width / 2 - ((m_rectWorking.Width / 2 - 5) * Math.Cos(Math.PI * (fltAngle / 180.00F)))));
383                 }
384                 g.DrawLine(new Pen(new SolidBrush(scaleColor), i % 2 == 0 ? 2 : 1), new PointF(fltX1, fltY1), new PointF(fltX2, fltY2));
385             }
386 
387             //值文字和固定文字
388             if (textLocation != MeterTextLocation.None)
389             {
390                 string str = m_value.ToString("0.##");
391                 var txtSize = g.MeasureString(str, textFont);
392                 float fltY = m_rectWorking.Top + m_rectWorking.Width / 4 - txtSize.Height / 2;
393                 float fltX = m_rectWorking.Left + m_rectWorking.Width / 2 - txtSize.Width / 2;
394                 g.DrawString(str, textFont, new SolidBrush(textColor), new PointF(fltX, fltY));
395 
396                 if (!string.IsNullOrEmpty(fixedText))
397                 {
398                     str = fixedText;
399                     txtSize = g.MeasureString(str, textFont);
400                     fltY = m_rectWorking.Top + m_rectWorking.Width / 4 + txtSize.Height / 2;
401                     fltX = m_rectWorking.Left + m_rectWorking.Width / 2 - txtSize.Width / 2;
402                     g.DrawString(str, textFont, new SolidBrush(textColor), new PointF(fltX, fltY));
403                 }
404             }
405 
406             //画指针
407             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));
408             g.FillEllipse(Brushes.Red, new Rectangle(m_rectWorking.Left + m_rectWorking.Width / 2 - 5, m_rectWorking.Top + m_rectWorking.Width / 2 - 5, 10, 10));
409             float fltValueAngle = (fltStartAngle + ((float)(m_value - minValue) / (float)(maxValue - minValue)) * (float)meterDegrees - 180) % 360;
410             float intValueY1 = (float)(m_rectWorking.Top + m_rectWorking.Width / 2 - ((m_rectWorking.Width / 2 - 30) * Math.Sin(Math.PI * (fltValueAngle / 180.00F))));
411             float intValueX1 = (float)(m_rectWorking.Left + (m_rectWorking.Width / 2 - ((m_rectWorking.Width / 2 - 30) * Math.Cos(Math.PI * (fltValueAngle / 180.00F)))));
412             g.DrawLine(new Pen(new SolidBrush(pointerColor), 3), intValueX1, intValueY1, m_rectWorking.Left + m_rectWorking.Width / 2, m_rectWorking.Top + m_rectWorking.Width / 2);
413         }
414     }
415 
416     /// <summary>
417     /// Enum MeterTextLocation
418     /// </summary>
419     public enum MeterTextLocation
420     {
421         /// <summary>
422         /// The none
423         /// </summary>
424         None,
425         /// <summary>
426         /// The top
427         /// </summary>
428         Top,
429         /// <summary>
430         /// The bottom
431         /// </summary>
432         Bottom
433     }
434 }

最后的话

如果你喜欢的话,请到 https://gitee.com/kwwwvagaa/net_winform_custom_control 点个星星吧

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券