69

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

 5 years ago
source link: https://www.cnblogs.com/bfyx/p/11457234.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

http://www.hzhcontrols.com

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

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

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

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

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

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

NuGet

Install-Package HZH_Controls

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

用处及效果

396919-20190904095508412-1725257055.png

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

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

View Code

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


Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK