This article demonstrates a complex analog-style thermometer control in C#. The control is in pure managed code. Most visual elements can be adjusted through the control's properties.
Due to the flexibility of the control, it can be used to display all sorts of data and not just degrees as used in this example.
The control consists of 2 classes:
The implementation is done in the
All painting is done in the
OnPaint method of the
Thermometer class. Every element has its own
Paint method and the methods are marked
protected override void OnPaint(PaintEventArgs e)
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.SmoothingMode = SmoothingMode.Default;
Painting the numbers
Most methods are straightforward, but aligning the numbers in the ellipse is somewhat tricky.
protected virtual void PaintNumbers(Graphics g)
double tmpAngle = StartAngle;
for (double d = Min; d<= Max; d+= Interval)
String text = Math.Round(d, Decimals).ToString();
PointF p =
tmpAngle, MeasureText(g, text, Font, (int)numberRect.Width));
tmpAngle -= NumberSpacing;
tmpAngle += NumberSpacing;
g.DrawString(text, Font, new SolidBrush(ForeColor), p);
The solution is to find the center point of the text and then calculate the offset based on the text's position in the ellipse and its dimensions.
private PointF CalcTextPosition(double a, SizeF size)
PointF p = PointInEllipse(numberRect, a);
p.X -= (float)((size.Width/2)*(1 + Math.Cos(Convert.ToRadians(a))));
p.Y -= (float)((size.Height/2)*(1 - Math.Sin(Convert.ToRadians(a))));
The private method
CalcTextPosition makes a call to
PointInEllipse. This method calculates a point in an ellipse based on the angle and the size of the ellipse, which is simple math.
private static PointF PointInEllipse(RectangleF rect , double angle)
double r1 = rect.Width/2;
double r2 = rect.Height/2;
double x =
(float)(r1 * Math.Cos(Convert.ToRadians(angle))) + r1 + rect.X;
double y =
-(float)(r2 * Math.Sin(Convert.ToRadians(angle))) + r2 + rect.Y;
return new PointF((float)x, (float)y);
Using the code
To test the control, download the demo project and then build and run it. To change the appearance of the control, use the properties:
Interval - The interval between each number on the control; this is a floating point number.
Max - The maximum on the scale.
Min - The minimum on the scale.
StartAngle - The starting point in degrees.
StoreMax - Show the maximum stored value (red arrow).
StoredMax - The stored maximum.
TextDescription - Set the lower text displayed on the control.
TextUnit - Set the text to describe the Units used.
Value - The value and point of the arrow.
ArrowColor - The color of the arrow.
BackColor - The inner color of the control.
BarsBetweenNumbers - The number of lines between two displayed numbers. Note that the alignment of the lines is dependent on the properties
BorderWidth - The width of the outer border.
ClockWise - Lay the numbers out clockwise or counter-clockwise.
Decimals - The number of decimals displayed; default is 0.
NumberSpacing - The spacing between the numbers in degrees.
- June 09, 2007: Initial release.
- July 08, 2007:
- Fixed missing dispose on some objects.
- Fixed a bug where the designer would hang if the control was added from the toolbar.
- Changed default text on Unit and Description property.
- Added the layout section in this document.
- Added a demo download.
- Removed solution from source control.