(五十四)c#Winform自定义控件-仪表盘-HZHControls
官网
前提
入行已经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 点个星星吧
作者:冰封一夏
出处:http://www.cnblogs.com/bfyx/
HZHControls官网:http://www.hzhcontrols.cn
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,
且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
GitHub:https://github.com/kwwwvagaa/NetWinformControl
码云:https://gitee.com/kwwwvagaa/net_winform_custom_control.git