前提
入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章。
GitHub:https://github.com/kwwwvagaa/NetWinformControl
码云:https://gitee.com/kwwwvagaa/net_winform_custom_control.git
如果觉得写的还行,请点个 star 支持一下吧
麻烦博客下方点个【推荐】,谢谢
NuGet
Install-Package HZH_Controls
目录
https://blog.csdn.net/kwwwvagaa/article/details/100586547
用处及效果
准备工作
依然用GID+画的,不懂请自行百度
开始
添加一个类UCThermometer,继承UserControl
添加一个枚举,来决定显示的温度单位
1 public enum TemperatureUnit
2 {
3 /// <summary>
4 /// 不显示
5 /// </summary>
6 None,
7 /// <summary>
8 /// 摄氏度
9 /// </summary>
10 C,
11 /// <summary>
12 /// 华氏度
13 /// </summary>
14 F,
15 /// <summary>
16 /// 开氏度
17 /// </summary>
18 K,
19 /// <summary>
20 /// 兰氏度
21 /// </summary>
22 R,
23 /// <summary>
24 /// 列氏度
25 /// </summary>
26 Re
27 }
添加一些属性
1 /// <summary>
2 /// The glass tube color
3 /// </summary>
4 private Color glassTubeColor = Color.FromArgb(211, 211, 211);
5
6 /// <summary>
7 /// Gets or sets the color of the glass tube.
8 /// </summary>
9 /// <value>The color of the glass tube.</value>
10 [Description("玻璃管颜色"), Category("自定义")]
11 public Color GlassTubeColor
12 {
13 get { return glassTubeColor; }
14 set
15 {
16 glassTubeColor = value;
17 Refresh();
18 }
19 }
20
21 /// <summary>
22 /// The mercury color
23 /// </summary>
24 private Color mercuryColor = Color.FromArgb(255, 77, 59);
25
26 /// <summary>
27 /// Gets or sets the color of the mercury.
28 /// </summary>
29 /// <value>The color of the mercury.</value>
30 [Description("水印颜色"), Category("自定义")]
31 public Color MercuryColor
32 {
33 get { return mercuryColor; }
34 set
35 {
36 mercuryColor = value;
37 Refresh();
38 }
39 }
40
41 /// <summary>
42 /// The minimum value
43 /// </summary>
44 private decimal minValue = 0;
45 /// <summary>
46 /// 左侧刻度最小值
47 /// </summary>
48 /// <value>The minimum value.</value>
49 [Description("左侧刻度最小值"), Category("自定义")]
50 public decimal MinValue
51 {
52 get { return minValue; }
53 set
54 {
55 minValue = value;
56 Refresh();
57 }
58 }
59
60 /// <summary>
61 /// The maximum value
62 /// </summary>
63 private decimal maxValue = 100;
64 /// <summary>
65 /// 左侧刻度最大值
66 /// </summary>
67 /// <value>The maximum value.</value>
68 [Description("左侧刻度最大值"), Category("自定义")]
69 public decimal MaxValue
70 {
71 get { return maxValue; }
72 set
73 {
74 maxValue = value;
75 Refresh();
76 }
77 }
78
79 /// <summary>
80 /// The m value
81 /// </summary>
82 private decimal m_value = 10;
83 /// <summary>
84 /// 左侧刻度值
85 /// </summary>
86 /// <value>The value.</value>
87 [Description("左侧刻度值"), Category("自定义")]
88 public decimal Value
89 {
90 get { return m_value; }
91 set
92 {
93 m_value = value;
94 Refresh();
95 }
96 }
97
98 /// <summary>
99 /// The split count
100 /// </summary>
101 private int splitCount = 0;
102 /// <summary>
103 /// 刻度分隔份数
104 /// </summary>
105 /// <value>The split count.</value>
106 [Description("刻度分隔份数"), Category("自定义")]
107 public int SplitCount
108 {
109 get { return splitCount; }
110 set
111 {
112 if (value <= 0)
113 return;
114 splitCount = value;
115 Refresh();
116 }
117 }
118
119 /// <summary>
120 /// 获取或设置控件显示的文字的字体。
121 /// </summary>
122 /// <value>The font.</value>
123 /// <PermissionSet>
124 /// <IPermission class="System.Security.Permissions.EnvironmentPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" />
125 /// <IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" />
126 /// <IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Flags="UnmanagedCode, ControlEvidence" />
127 /// <IPermission class="System.Diagnostics.PerformanceCounterPermission, System, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" />
128 /// </PermissionSet>
129 [Description("获取或设置控件显示的文字的字体"), Category("自定义")]
130 public override Font Font
131 {
132 get
133 {
134 return base.Font;
135 }
136 set
137 {
138 base.Font = value;
139 Refresh();
140 }
141 }
142
143 /// <summary>
144 /// 获取或设置控件的前景色。
145 /// </summary>
146 /// <value>The color of the fore.</value>
147 /// <PermissionSet>
148 /// <IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" />
149 /// </PermissionSet>
150 [Description("获取或设置控件的文字及刻度颜色"), Category("自定义")]
151 public override System.Drawing.Color ForeColor
152 {
153 get
154 {
155 return base.ForeColor;
156 }
157 set
158 {
159 base.ForeColor = value;
160 Refresh();
161 }
162 }
163
164 /// <summary>
165 /// The left temperature unit
166 /// </summary>
167 private TemperatureUnit leftTemperatureUnit = TemperatureUnit.C;
168 /// <summary>
169 /// 左侧刻度单位,不可为none
170 /// </summary>
171 /// <value>The left temperature unit.</value>
172 [Description("左侧刻度单位,不可为none"), Category("自定义")]
173 public TemperatureUnit LeftTemperatureUnit
174 {
175 get { return leftTemperatureUnit; }
176 set
177 {
178 if (value == TemperatureUnit.None)
179 return;
180 leftTemperatureUnit = value;
181 Refresh();
182 }
183 }
184
185 /// <summary>
186 /// The right temperature unit
187 /// </summary>
188 private TemperatureUnit rightTemperatureUnit = TemperatureUnit.C;
189 /// <summary>
190 /// 右侧刻度单位,当为none时,不显示
191 /// </summary>
192 /// <value>The right temperature unit.</value>
193 [Description("右侧刻度单位,当为none时,不显示"), Category("自定义")]
194 public TemperatureUnit RightTemperatureUnit
195 {
196 get { return rightTemperatureUnit; }
197 set
198 {
199 rightTemperatureUnit = value;
200 Refresh();
201 }
202 }
203
204 /// <summary>
205 /// The m rect working
206 /// </summary>
207 Rectangle m_rectWorking;
208 /// <summary>
209 /// The m rect left
210 /// </summary>
211 Rectangle m_rectLeft;
212 /// <summary>
213 /// The m rect right
214 /// </summary>
215 Rectangle m_rectRight;
改变大小时,设定画图区域
1 void UCThermometer_SizeChanged(object sender, EventArgs e)
2 {
3 m_rectWorking = new Rectangle(this.Width / 2 - this.Width / 8, this.Width / 4, this.Width / 4, this.Height - this.Width / 2);
4 m_rectLeft = new Rectangle(0, m_rectWorking.Top + m_rectWorking.Width / 2, (this.Width - this.Width / 4) / 2 - 2, m_rectWorking.Height - m_rectWorking.Width * 2);
5 m_rectRight = new Rectangle(this.Width - (this.Width - this.Width / 4) / 2 + 2, m_rectWorking.Top + m_rectWorking.Width / 2, (this.Width - this.Width / 4) / 2 - 2, m_rectWorking.Height - m_rectWorking.Width * 2);
6 }
重绘
1 protected override void OnPaint(PaintEventArgs e)
2 {
3 base.OnPaint(e);
4 var g = e.Graphics;
5 g.SetGDIHigh();
6
7 //玻璃管管
8 GraphicsPath path = new GraphicsPath();
9 path.AddLine(m_rectWorking.Left, m_rectWorking.Bottom, m_rectWorking.Left, m_rectWorking.Top + m_rectWorking.Width / 2);
10 path.AddArc(new Rectangle(m_rectWorking.Left, m_rectWorking.Top, m_rectWorking.Width, m_rectWorking.Width), 180, 180);
11 path.AddLine(m_rectWorking.Right, m_rectWorking.Top + m_rectWorking.Width / 2, m_rectWorking.Right, m_rectWorking.Bottom);
12 path.CloseAllFigures();
13 g.FillPath(new SolidBrush(glassTubeColor), path);
14
15 //底部
16 var rectDi = new Rectangle(this.Width / 2 - m_rectWorking.Width, m_rectWorking.Bottom - m_rectWorking.Width - 2, m_rectWorking.Width * 2, m_rectWorking.Width * 2);
17 g.FillEllipse(new SolidBrush(glassTubeColor), rectDi);
18 g.FillEllipse(new SolidBrush(mercuryColor), new Rectangle(rectDi.Left + 4, rectDi.Top + 4, rectDi.Width - 8, rectDi.Height - 8));
19
20 //刻度
21 decimal decSplit = (maxValue - minValue) / splitCount;
22 decimal decSplitHeight = m_rectLeft.Height / splitCount;
23 for (int i = 0; i <= splitCount; i++)
24 {
25 g.DrawLine(new Pen(new SolidBrush(ForeColor), 1), new PointF(m_rectLeft.Left + 2, (float)(m_rectLeft.Bottom - decSplitHeight * i)), new PointF(m_rectLeft.Right, (float)(m_rectLeft.Bottom - decSplitHeight * i)));
26
27 var valueLeft = (minValue + decSplit * i).ToString("0.##");
28 var sizeLeft = g.MeasureString(valueLeft, Font);
29 g.DrawString(valueLeft, Font, new SolidBrush(ForeColor), new PointF(m_rectLeft.Left, m_rectLeft.Bottom - (float)decSplitHeight * i - sizeLeft.Height - 1));
30
31 if (rightTemperatureUnit != TemperatureUnit.None)
32 {
33 g.DrawLine(new Pen(new SolidBrush(Color.Black), 1), new PointF(m_rectRight.Left + 2, (float)(m_rectRight.Bottom - decSplitHeight * i)), new PointF(m_rectRight.Right, (float)(m_rectRight.Bottom - decSplitHeight * i)));
34 var valueRight = GetRightValue(minValue + decSplit * i).ToString("0.##");
35 var sizeRight = g.MeasureString(valueRight, Font);
36 g.DrawString(valueRight, Font, new SolidBrush(ForeColor), new PointF(m_rectRight.Right - sizeRight.Width - 1, m_rectRight.Bottom - (float)decSplitHeight * i - sizeRight.Height - 1));
37 }
38 if (i != splitCount)
39 {
40 if (decSplitHeight > 40)
41 {
42 var decSp1 = decSplitHeight / 10;
43 for (int j = 1; j < 10; j++)
44 {
45 if (j == 5)
46 {
47 g.DrawLine(new Pen(new SolidBrush(ForeColor), 1), new PointF(m_rectLeft.Right - 10, (m_rectLeft.Bottom - (float)decSplitHeight * i - ((float)decSp1 * j))), new PointF(m_rectLeft.Right, (m_rectLeft.Bottom - (float)decSplitHeight * i - ((float)decSp1 * j))));
48 if (rightTemperatureUnit != TemperatureUnit.None)
49 {
50 g.DrawLine(new Pen(new SolidBrush(ForeColor), 1), new PointF(m_rectRight.Left + 10, (m_rectRight.Bottom - (float)decSplitHeight * i - ((float)decSp1 * j))), new PointF(m_rectRight.Left, (m_rectRight.Bottom - (float)decSplitHeight * i - ((float)decSp1 * j))));
51 }
52 }
53 else
54 {
55 g.DrawLine(new Pen(new SolidBrush(ForeColor), 1), new PointF(m_rectLeft.Right - 5, (m_rectLeft.Bottom - (float)decSplitHeight * i - ((float)decSp1 * j))), new PointF(m_rectLeft.Right, (m_rectLeft.Bottom - (float)decSplitHeight * i - ((float)decSp1 * j))));
56 if (rightTemperatureUnit != TemperatureUnit.None)
57 {
58 g.DrawLine(new Pen(new SolidBrush(ForeColor), 1), new PointF(m_rectRight.Left + 5, (m_rectRight.Bottom - (float)decSplitHeight * i - ((float)decSp1 * j))), new PointF(m_rectRight.Left, (m_rectRight.Bottom - (float)decSplitHeight * i - ((float)decSp1 * j))));
59 }
60 }
61 }
62 }
63 else if (decSplitHeight > 10)
64 {
65 g.DrawLine(new Pen(new SolidBrush(ForeColor), 1), new PointF(m_rectLeft.Right - 5, (m_rectLeft.Bottom - (float)decSplitHeight * i - (float)decSplitHeight / 2)), new PointF(m_rectLeft.Right, (m_rectLeft.Bottom - (float)decSplitHeight * i - (float)decSplitHeight / 2)));
66 if (rightTemperatureUnit != TemperatureUnit.None)
67 {
68 g.DrawLine(new Pen(new SolidBrush(ForeColor), 1), new PointF(m_rectRight.Left + 5, (m_rectRight.Bottom - (float)decSplitHeight * i - (float)decSplitHeight / 2)), new PointF(m_rectRight.Left, (m_rectRight.Bottom - (float)decSplitHeight * i - (float)decSplitHeight / 2)));
69 }
70 }
71 }
72 }
73 //单位
74 string strLeftUnit = GetUnitChar(leftTemperatureUnit);
75 g.DrawString(strLeftUnit, Font, new SolidBrush(ForeColor), new PointF(m_rectLeft.Left + 2, 2));
76 if (rightTemperatureUnit != TemperatureUnit.None)
77 {
78 string strRightUnit = GetUnitChar(rightTemperatureUnit);
79 var rightSize = g.MeasureString(strRightUnit, Font);
80 g.DrawString(strRightUnit, Font, new SolidBrush(ForeColor), new PointF(m_rectRight.Right - 2 - rightSize.Width, 2));
81 }
82 //值
83 float fltHeightValue = (float)(Value / (maxValue - minValue) * m_rectLeft.Height);
84 RectangleF rectValue = new RectangleF(m_rectWorking.Left + 4, m_rectLeft.Top + (m_rectLeft.Height - fltHeightValue), m_rectWorking.Width - 8, fltHeightValue + (m_rectWorking.Height - m_rectWorking.Width / 2 - m_rectLeft.Height));
85 g.FillRectangle(new SolidBrush(mercuryColor), rectValue);
86
87
88 var sizeValue = g.MeasureString(m_value.ToString("0.##"), Font);
89 g.DrawString(m_value.ToString("0.##"), Font, new SolidBrush(Color.White), new PointF(rectDi.Left + (rectDi.Width - sizeValue.Width) / 2, rectDi.Top + (rectDi.Height - sizeValue.Height) / 2 + 1));
90 }
辅助函数
1 private string GetUnitChar(TemperatureUnit unit)
2 {
3 string strUnit = "℃";
4 switch (unit)
5 {
6 case TemperatureUnit.C:
7 strUnit = "℃";
8 break;
9 case TemperatureUnit.F:
10 strUnit = "℉";
11 break;
12 case TemperatureUnit.K:
13 strUnit = "K";
14 break;
15 case TemperatureUnit.R:
16 strUnit = "°R";
17 break;
18 case TemperatureUnit.Re:
19 strUnit = "°Re";
20 break;
21 }
22 return strUnit;
23 }
24
25 private decimal GetRightValue(decimal decValue)
26 {
27 //先将左侧的换算为摄氏度
28 var dec = decValue;
29 switch (leftTemperatureUnit)
30 {
31 case TemperatureUnit.F:
32 dec = (decValue - 32) / (9M / 5M);
33 break;
34 case TemperatureUnit.K:
35 dec = decValue - 273;
36 break;
37 case TemperatureUnit.R:
38 dec = decValue / (5M / 9M) - 273.15M;
39 break;
40 case TemperatureUnit.Re:
41 dec = decValue / 1.25M;
42 break;
43 default:
44 break;
45 }
46
47 switch (rightTemperatureUnit)
48 {
49 case TemperatureUnit.C:
50 return dec;
51 case TemperatureUnit.F:
52 return 9M / 5M * dec + 32;
53 case TemperatureUnit.K:
54 return dec + 273;
55 case TemperatureUnit.R:
56 return (dec + 273.15M) * (5M / 9M);
57 case TemperatureUnit.Re:
58 return dec * 1.25M;
59 }
60 return decValue;
61 }
完整代码
// ***********************************************************************
// Assembly : HZH_Controls
// Created : 2019-09-10
//
// ***********************************************************************
// <copyright file="UCThermometer.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 UCThermometer.
/// Implements the <see cref="System.Windows.Forms.UserControl" />
/// </summary>
/// <seealso cref="System.Windows.Forms.UserControl" />
public class UCThermometer : UserControl
{
/// <summary>
/// The glass tube color
/// </summary>
private Color glassTubeColor = Color.FromArgb(211, 211, 211);
/// <summary>
/// Gets or sets the color of the glass tube.
/// </summary>
/// <value>The color of the glass tube.</value>
[Description("玻璃管颜色"), Category("自定义")]
public Color GlassTubeColor
{
get { return glassTubeColor; }
set
{
glassTubeColor = value;
Refresh();
}
}
/// <summary>
/// The mercury color
/// </summary>
private Color mercuryColor = Color.FromArgb(255, 77, 59);
/// <summary>
/// Gets or sets the color of the mercury.
/// </summary>
/// <value>The color of the mercury.</value>
[Description("水印颜色"), Category("自定义")]
public Color MercuryColor
{
get { return mercuryColor; }
set
{
mercuryColor = value;
Refresh();
}
}
/// <summary>
/// The minimum value
/// </summary>
private decimal minValue = 0;
/// <summary>
/// 左侧刻度最小值
/// </summary>
/// <value>The minimum value.</value>
[Description("左侧刻度最小值"), Category("自定义")]
public decimal MinValue
{
get { return minValue; }
set
{
minValue = value;
Refresh();
}
}
/// <summary>
/// The maximum value
/// </summary>
private decimal maxValue = 100;
/// <summary>
/// 左侧刻度最大值
/// </summary>
/// <value>The maximum value.</value>
[Description("左侧刻度最大值"), Category("自定义")]
public decimal MaxValue
{
get { return maxValue; }
set
{
maxValue = value;
Refresh();
}
}
/// <summary>
/// The m value
/// </summary>
private decimal m_value = 10;
/// <summary>
/// 左侧刻度值
/// </summary>
/// <value>The value.</value>
[Description("左侧刻度值"), Category("自定义")]
public decimal Value
{
get { return m_value; }
set
{
m_value = value;
Refresh();
}
}
/// <summary>
/// The split count
/// </summary>
private int splitCount = 0;
/// <summary>
/// 刻度分隔份数
/// </summary>
/// <value>The split count.</value>
[Description("刻度分隔份数"), Category("自定义")]
public int SplitCount
{
get { return splitCount; }
set
{
if (value <= 0)
return;
splitCount = 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();
}
}
/// <summary>
/// 获取或设置控件的前景色。
/// </summary>
/// <value>The color of the fore.</value>
/// <PermissionSet>
/// <IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" />
/// </PermissionSet>
[Description("获取或设置控件的文字及刻度颜色"), Category("自定义")]
public override System.Drawing.Color ForeColor
{
get
{
return base.ForeColor;
}
set
{
base.ForeColor = value;
Refresh();
}
}
/// <summary>
/// The left temperature unit
/// </summary>
private TemperatureUnit leftTemperatureUnit = TemperatureUnit.C;
/// <summary>
/// 左侧刻度单位,不可为none
/// </summary>
/// <value>The left temperature unit.</value>
[Description("左侧刻度单位,不可为none"), Category("自定义")]
public TemperatureUnit LeftTemperatureUnit
{
get { return leftTemperatureUnit; }
set
{
if (value == TemperatureUnit.None)
return;
leftTemperatureUnit = value;
Refresh();
}
}
/// <summary>
/// The right temperature unit
/// </summary>
private TemperatureUnit rightTemperatureUnit = TemperatureUnit.C;
/// <summary>
/// 右侧刻度单位,当为none时,不显示
/// </summary>
/// <value>The right temperature unit.</value>
[Description("右侧刻度单位,当为none时,不显示"), Category("自定义")]
public TemperatureUnit RightTemperatureUnit
{
get { return rightTemperatureUnit; }
set
{
rightTemperatureUnit = value;
Refresh();
}
}
/// <summary>
/// The m rect working
/// </summary>
Rectangle m_rectWorking;
/// <summary>
/// The m rect left
/// </summary>
Rectangle m_rectLeft;
/// <summary>
/// The m rect right
/// </summary>
Rectangle m_rectRight;
/// <summary>
/// Initializes a new instance of the <see cref="UCThermometer"/> class.
/// </summary>
public UCThermometer()
{
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.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
this.SizeChanged += UCThermometer_SizeChanged;
this.Size = new Size(70, 200);
}
/// <summary>
/// Handles the SizeChanged event of the UCThermometer control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
void UCThermometer_SizeChanged(object sender, EventArgs e)
{
m_rectWorking = new Rectangle(this.Width / 2 - this.Width / 8, this.Width / 4, this.Width / 4, this.Height - this.Width / 2);
m_rectLeft = new Rectangle(0, m_rectWorking.Top + m_rectWorking.Width / 2, (this.Width - this.Width / 4) / 2 - 2, m_rectWorking.Height - m_rectWorking.Width * 2);
m_rectRight = new Rectangle(this.Width - (this.Width - this.Width / 4) / 2 + 2, m_rectWorking.Top + m_rectWorking.Width / 2, (this.Width - this.Width / 4) / 2 - 2, m_rectWorking.Height - m_rectWorking.Width * 2);
}
/// <summary>
/// 引发 <see cref="E:System.Windows.Forms.Control.Paint" /> 事件。
/// </summary>
/// <param name="e">包含事件数据的 <see cref="T:System.Windows.Forms.PaintEventArgs" />。</param>
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
var g = e.Graphics;
g.SetGDIHigh();
//玻璃管管
GraphicsPath path = new GraphicsPath();
path.AddLine(m_rectWorking.Left, m_rectWorking.Bottom, m_rectWorking.Left, m_rectWorking.Top + m_rectWorking.Width / 2);
path.AddArc(new Rectangle(m_rectWorking.Left, m_rectWorking.Top, m_rectWorking.Width, m_rectWorking.Width), 180, 180);
path.AddLine(m_rectWorking.Right, m_rectWorking.Top + m_rectWorking.Width / 2, m_rectWorking.Right, m_rectWorking.Bottom);
path.CloseAllFigures();
g.FillPath(new SolidBrush(glassTubeColor), path);
//底部
var rectDi = new Rectangle(this.Width / 2 - m_rectWorking.Width, m_rectWorking.Bottom - m_rectWorking.Width - 2, m_rectWorking.Width * 2, m_rectWorking.Width * 2);
g.FillEllipse(new SolidBrush(glassTubeColor), rectDi);
g.FillEllipse(new SolidBrush(mercuryColor), new Rectangle(rectDi.Left + 4, rectDi.Top + 4, rectDi.Width - 8, rectDi.Height - 8));
//刻度
decimal decSplit = (maxValue - minValue) / splitCount;
decimal decSplitHeight = m_rectLeft.Height / splitCount;
for (int i = 0; i <= splitCount; i++)
{
g.DrawLine(new Pen(new SolidBrush(ForeColor), 1), new PointF(m_rectLeft.Left + 2, (float)(m_rectLeft.Bottom - decSplitHeight * i)), new PointF(m_rectLeft.Right, (float)(m_rectLeft.Bottom - decSplitHeight * i)));
var valueLeft = (minValue + decSplit * i).ToString("0.##");
var sizeLeft = g.MeasureString(valueLeft, Font);
g.DrawString(valueLeft, Font, new SolidBrush(ForeColor), new PointF(m_rectLeft.Left, m_rectLeft.Bottom - (float)decSplitHeight * i - sizeLeft.Height - 1));
if (rightTemperatureUnit != TemperatureUnit.None)
{
g.DrawLine(new Pen(new SolidBrush(Color.Black), 1), new PointF(m_rectRight.Left + 2, (float)(m_rectRight.Bottom - decSplitHeight * i)), new PointF(m_rectRight.Right, (float)(m_rectRight.Bottom - decSplitHeight * i)));
var valueRight = GetRightValue(minValue + decSplit * i).ToString("0.##");
var sizeRight = g.MeasureString(valueRight, Font);
g.DrawString(valueRight, Font, new SolidBrush(ForeColor), new PointF(m_rectRight.Right - sizeRight.Width - 1, m_rectRight.Bottom - (float)decSplitHeight * i - sizeRight.Height - 1));
}
if (i != splitCount)
{
if (decSplitHeight > 40)
{
var decSp1 = decSplitHeight / 10;
for (int j = 1; j < 10; j++)
{
if (j == 5)
{
g.DrawLine(new Pen(new SolidBrush(ForeColor), 1), new PointF(m_rectLeft.Right - 10, (m_rectLeft.Bottom - (float)decSplitHeight * i - ((float)decSp1 * j))), new PointF(m_rectLeft.Right, (m_rectLeft.Bottom - (float)decSplitHeight * i - ((float)decSp1 * j))));
if (rightTemperatureUnit != TemperatureUnit.None)
{
g.DrawLine(new Pen(new SolidBrush(ForeColor), 1), new PointF(m_rectRight.Left + 10, (m_rectRight.Bottom - (float)decSplitHeight * i - ((float)decSp1 * j))), new PointF(m_rectRight.Left, (m_rectRight.Bottom - (float)decSplitHeight * i - ((float)decSp1 * j))));
}
}
else
{
g.DrawLine(new Pen(new SolidBrush(ForeColor), 1), new PointF(m_rectLeft.Right - 5, (m_rectLeft.Bottom - (float)decSplitHeight * i - ((float)decSp1 * j))), new PointF(m_rectLeft.Right, (m_rectLeft.Bottom - (float)decSplitHeight * i - ((float)decSp1 * j))));
if (rightTemperatureUnit != TemperatureUnit.None)
{
g.DrawLine(new Pen(new SolidBrush(ForeColor), 1), new PointF(m_rectRight.Left + 5, (m_rectRight.Bottom - (float)decSplitHeight * i - ((float)decSp1 * j))), new PointF(m_rectRight.Left, (m_rectRight.Bottom - (float)decSplitHeight * i - ((float)decSp1 * j))));
}
}
}
}
else if (decSplitHeight > 10)
{
g.DrawLine(new Pen(new SolidBrush(ForeColor), 1), new PointF(m_rectLeft.Right - 5, (m_rectLeft.Bottom - (float)decSplitHeight * i - (float)decSplitHeight / 2)), new PointF(m_rectLeft.Right, (m_rectLeft.Bottom - (float)decSplitHeight * i - (float)decSplitHeight / 2)));
if (rightTemperatureUnit != TemperatureUnit.None)
{
g.DrawLine(new Pen(new SolidBrush(ForeColor), 1), new PointF(m_rectRight.Left + 5, (m_rectRight.Bottom - (float)decSplitHeight * i - (float)decSplitHeight / 2)), new PointF(m_rectRight.Left, (m_rectRight.Bottom - (float)decSplitHeight * i - (float)decSplitHeight / 2)));
}
}
}
}
//单位
string strLeftUnit = GetUnitChar(leftTemperatureUnit);
g.DrawString(strLeftUnit, Font, new SolidBrush(ForeColor), new PointF(m_rectLeft.Left + 2, 2));
if (rightTemperatureUnit != TemperatureUnit.None)
{
string strRightUnit = GetUnitChar(rightTemperatureUnit);
var rightSize = g.MeasureString(strRightUnit, Font);
g.DrawString(strRightUnit, Font, new SolidBrush(ForeColor), new PointF(m_rectRight.Right - 2 - rightSize.Width, 2));
}
//值
float fltHeightValue = (float)(Value / (maxValue - minValue) * m_rectLeft.Height);
RectangleF rectValue = new RectangleF(m_rectWorking.Left + 4, m_rectLeft.Top + (m_rectLeft.Height - fltHeightValue), m_rectWorking.Width - 8, fltHeightValue + (m_rectWorking.Height - m_rectWorking.Width / 2 - m_rectLeft.Height));
g.FillRectangle(new SolidBrush(mercuryColor), rectValue);
var sizeValue = g.MeasureString(m_value.ToString("0.##"), Font);
g.DrawString(m_value.ToString("0.##"), Font, new SolidBrush(Color.White), new PointF(rectDi.Left + (rectDi.Width - sizeValue.Width) / 2, rectDi.Top + (rectDi.Height - sizeValue.Height) / 2 + 1));
}
private string GetUnitChar(TemperatureUnit unit)
{
string strUnit = "℃";
switch (unit)
{
case TemperatureUnit.C:
strUnit = "℃";
break;
case TemperatureUnit.F:
strUnit = "℉";
break;
case TemperatureUnit.K:
strUnit = "K";
break;
case TemperatureUnit.R:
strUnit = "°R";
break;
case TemperatureUnit.Re:
strUnit = "°Re";
break;
}
return strUnit;
}
private decimal GetRightValue(decimal decValue)
{
//先将左侧的换算为摄氏度
var dec = decValue;
switch (leftTemperatureUnit)
{
case TemperatureUnit.F:
dec = (decValue - 32) / (9M / 5M);
break;
case TemperatureUnit.K:
dec = decValue - 273;
break;
case TemperatureUnit.R:
dec = decValue / (5M / 9M) - 273.15M;
break;
case TemperatureUnit.Re:
dec = decValue / 1.25M;
break;
default:
break;
}
switch (rightTemperatureUnit)
{
case TemperatureUnit.C:
return dec;
case TemperatureUnit.F:
return 9M / 5M * dec + 32;
case TemperatureUnit.K:
return dec + 273;
case TemperatureUnit.R:
return (dec + 273.15M) * (5M / 9M);
case TemperatureUnit.Re:
return dec * 1.25M;
}
return decValue;
}
}
/// <summary>
/// Enum TemperatureUnit
/// </summary>
public enum TemperatureUnit
{
/// <summary>
/// 不显示
/// </summary>
None,
/// <summary>
/// 摄氏度
/// </summary>
C,
/// <summary>
/// 华氏度
/// </summary>
F,
/// <summary>
/// 开氏度
/// </summary>
K,
/// <summary>
/// 兰氏度
/// </summary>
R,
/// <summary>
/// 列氏度
/// </summary>
Re
}
}
最后的话
如果你喜欢的话,请到 https://gitee.com/kwwwvagaa/net_winform_custom_control 点个星星吧