Analog clock in C#
A C# program that uses the .NET runtime to draw an analog clock that updates every second.

// clock - Analog clock demo.
// Author: Po Shan Cheah
// Last updated: August 14, 2003
//
// Compile with: csc /t:winexe clock.cs
namespace Clock {
using System;
using System.Drawing;
using System.Windows.Forms;
class Clock : Form {
/// <summary>Timer event handler. Will be called every second to redraw
/// the clock.</summary>
void Tick(Object o, EventArgs e) {
Invalidate();
// Invalidate() by itself does not trigger a repaint.
Update();
}
/// <summary>Clock constructor</summary>
Clock() {
// Set window title and name.
Text = "Clock Demo";
Name = "Clock";
// Activate double-buffering.
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.DoubleBuffer, true);
// Invalidate on resize.
SetStyle(ControlStyles.ResizeRedraw, true);
// Start the timer. Tell it to call Tick().
Timer timer = new Timer();
timer.Tick += new EventHandler(Tick);
timer.Interval = 1000;
timer.Start();
} // Clock
static Color background = Color.DarkBlue;
static Color foreground = Color.Yellow;
int xmid;
int ymid;
int clockradius;
/// <summary>Polar to Rectangular coordinate conversion.</summary>
/// <remarks>xmid needs to be set before calling.</remarks>
/// <param name="dist">Distance from center</param>
/// <param name="angle">Angle in radians</param>
/// <returns>the X coordinate</returns>
int polarx(double dist, double angle) {
return xmid + (int) Math.Round(dist * Math.Sin(angle));
}
/// <summary>Polar to Rectangular coordinate conversion.</summary>
/// <remarks>ymid needs to be set before calling.</remarks>
/// <param name="dist">Distance from center</param>
/// <param name="angle">Angle in radians</param>
/// <returns>the Y coordinate</returns>
int polary(double dist, double angle) {
return ymid - (int) Math.Round(dist * Math.Cos(angle));
}
/// <summary>Displays text centered on a specific coordinate.
/// Takes into account text width and height.</summary>
/// <param name="g">Graphics context</param>
/// <param name="font">Font to use to draw the text</param>
/// <param name="text">Text to be drawn</param>
/// <param name="x">Where to draw the text</param>
/// <param name="y">Where to draw the text</param>
void CenterText(Graphics g, Font font, string text, int x, int y) {
SizeF size = g.MeasureString(text, font);
g.DrawString(text, font, new SolidBrush(foreground),
new PointF(x - size.Width / 2, y - size.Height / 2));
}
/// <summary>Draw a clock hand.</summary>
/// <param name="g">Graphics context</param>
/// <param name="length">Length of hand from center</param>
/// <param name="width">Width of hand at center</param>
/// <param name="bkwidth">Length of hand on the other side of
/// center</param>
/// <param name="angle">Angle in radians</param>
void DrawHand(Graphics g,
int length, int width, int bkwidth,
double angle) {
g.DrawPolygon(new Pen(foreground),
new Point[] {
new Point(polarx(-bkwidth, angle),
polary(-bkwidth, angle)),
new Point(polarx(width, angle + Math.PI / 2),
polary(width, angle + Math.PI / 2)),
new Point(polarx(length, angle),
polary(length, angle)),
new Point(polarx(width, angle - Math.PI / 2),
polary(width, angle - Math.PI / 2)) });
} // DrawHand
/// <summary>Draw the three clock hands.</summary>
/// <remarks>clockradius must be set before calling</remarks>
/// <param name="g">Graphics context</param>
/// <param name="hour">Hours</param>
/// <param name="min">Minutes</param>
/// <param name="sec">Seconds</param>
void DrawHands(Graphics g, int hour, int min, int sec) {
DrawHand(g,
(int) (0.6 * clockradius),
(int) (0.075 * clockradius),
(int) (0.1 * clockradius),
(hour + min / 60.0) * 2 * Math.PI / 12);
DrawHand(g,
(int) (0.9 * clockradius),
(int) (0.075 * clockradius),
(int) (0.15 * clockradius),
(min + sec / 60.0) * 2 * Math.PI / 60);
DrawHand(g,
(int) (0.9 * clockradius),
(int) (0.025 * clockradius),
(int) (0.15 * clockradius),
sec * 2 * Math.PI / 60);
} // DrawHands
/// <summary>Draw the clock face and hands</summary>
/// <param name="g">Graphics context</param>
/// <param name="width">Width of drawing area</param>
/// <param name="height">Height of drawing area</param>
void DrawClock(Graphics g, int width, int height) {
g.Clear(background);
// Clock has to fit the drawing area and be round.
xmid = width / 2;
ymid = height / 2;
clockradius = (int) (Math.Min(xmid, ymid) * 0.95);
int fontsize = clockradius / 7;
if (fontsize < 1)
fontsize = 1;
Font font = new Font("SansSerif", fontsize);
// Draw tick marks and numbers.
for (int i = 0; i < 360; i += 6) {
double rad = i * Math.PI / 180;
if (i % 30 == 0) {
g.DrawLine(new Pen(foreground),
new Point(polarx(clockradius, rad),
polary(clockradius, rad)),
new Point(polarx(0.925 * clockradius, rad),
polary(0.925 * clockradius, rad)));
int hour = i == 0 ? 12 : i / 30;
CenterText(g, font, hour.ToString(),
polarx(0.8 * clockradius, rad),
polary(0.8 * clockradius, rad));
}
else {
g.DrawLine(new Pen(foreground),
new Point(polarx(clockradius, rad),
polary(clockradius, rad)),
new Point(polarx(0.975 * clockradius, rad),
polary(0.975 * clockradius, rad)));
}
}
// Draw hands showing the current time.
DateTime time = DateTime.Now;
DrawHands(g, time.Hour % 12, time.Minute, time.Second);
} // DrawClock
/// <summary>Override the paint event handler to draw the clock
/// face.</summary>
/// <param name="e">Paint event</param>
protected override void OnPaint(PaintEventArgs e) {
DrawClock(e.Graphics, ClientRectangle.Width, ClientRectangle.Height);
}
/// <summary>Entry point</summary>
static void Main() {
Application.Run(new Clock());
}
} // class Clock
} // namespace Clock
// The End
