Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

How to build a Clock control

, 9 Sep 2002
This is a quick guide on how to create your own customizable clock control
clock_dem.zip
ClockDemo
App.ico
ClockDemo.csproj.user
ClockDemo.exe
ClockDemo.suo
clock_src.zip
/*
 Author:	Serban Iulian
 Date:		1 September 2002
 Class:		Clock
 e-mail:	iulianserban@hotmail.com
 Version:	1.0 
*/

using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;

namespace ClockDemo
{
	/// <summary>
	/// Summary description for CustomControl1.
	/// </summary>
	public class Clock : System.Windows.Forms.Control
	{
		private System.Windows.Forms.Timer timer;
		private System.ComponentModel.IContainer components;
	
		public Clock()
		{
			//Set Up the Refresh Timer
			timer = new System.Windows.Forms.Timer();
			timer.Interval = 1000;
			timer.Enabled = true;
			timer.Tick+= new System.EventHandler(this.Timer_Tick);
			
			//The Default Parameters are set in case they are not Modified by the User

			//The point in the center of the clock
			m_ptCenterPoint = new Point(50,50);

			//The Radius of the perimeter pots
			m_nClockRadius = 100;
			//The Brush used to draw the perimeter dots
			m_brPerimeterPoints = Brushes.Black;
			//The Diameter of the small dots of the perimeter
			m_nSmallDotSize = 4;
			//The Diameter of the big dots of the perimeter
			m_nBigDotSize = 8;
			//The Offset of the perimeter numbers
			m_nNumberOffset = -10;
			//The Radius of the perimeter numbers
			m_nNumberRadius = m_nClockRadius + 24;


			//The Font used to draw the perimeter numbers
			m_ftNumbers = new Font("Verdana",16);
			//The Font used to draw the Bottom Number Clock
			m_ftNumberClock = new Font("Verdana",16);
			//Boolean value indicating if the perimeter numbers are visible
			m_bNumbers = true;
			//The Brush used to draw the perimeter numbers
			m_brNumbers = Brushes.Black;
			//The Length of the Hour Pointer
			m_nHourPointerLength = 60;
			//The Length of the Minute Pointer
			m_nMinutePointerLength = 80;
			//The Length of the Second Pointer
			m_nSecondPointerLength = 90;

			//The Brush Size of the Hour Pointer
			m_nHourPointerSize = 20;
			//The Brush Size of the Minute Pointer
			m_nMinutePointerSize = 16;
			//The Brush Size of the Second Pointer
			m_nSecondPointerSize = 12;

			//The Brush used to draw the Hour Pointer
			m_brHourPointer = Brushes.Blue;
			//The Brush used to draw the Minute Pointer
			m_brMinutePointer = Brushes.Red;
			//The Brush used to draw the Second Pointer
			m_brSecondPointer = Brushes.Green;
			//Boolean value indicating if the Bottom Number Clock is Visible
			m_bNumberClock = true;

			//Boolean value indicating if the Background Image is visible
			m_bBackImage = false;

			//m_imgBackGround = Image.FromFile("e:\\gradient.jpg");

	}
/// <summary>
/// This is called when the Timer Ticks and Refreshes the Clock
/// </summary>
/// <param name="Sender"></param>
/// <param name="e"></param>
		
		private void Timer_Tick(object Sender, EventArgs e)
		 {
			//Refresh the Clock
			this.Invalidate();
            this.Update();
		 }

		private void InitializeComponent()
		{
			this.components = new System.ComponentModel.Container();
			this.timer = new System.Windows.Forms.Timer(this.components);
			// 
			// timer
			// 
			this.timer.Interval = 1000;

		}
/// <summary>
/// Scale To Fit Scales the Clock with it`s default dimensional parameters to fit into the Size object
/// Adjusts the numeric Parameters Only. The Colors and Booleans remain unchanged
/// </summary>
/// <param name="sSize"></param>
		
		public void ScaleToFit(System.Drawing.Size sSize)
		{
			float ScaleFactor = (float)sSize.Width/(140);
			m_nClockRadius =(int)(50*ScaleFactor);
			
			m_nOffset = 0;//(int)(20*ScaleFactor);


			m_nSmallDotSize = (int) ( 2*ScaleFactor);
			m_nBigDotSize = (int) ( 4*ScaleFactor);
			m_nNumberOffset = (int) ( -5*ScaleFactor);
			m_nNumberRadius = (int) ( m_nClockRadius + 12*ScaleFactor);

			m_ftNumbers = new Font("Verdana",(int)(8*ScaleFactor));
			m_ftNumberClock = new Font("Verdana",(int)(8*ScaleFactor));

			m_nHourPointerLength = (int) ( 30*ScaleFactor);
			m_nMinutePointerLength = (int) ( 40*ScaleFactor);
			m_nSecondPointerLength = (int) ( 45*ScaleFactor);

			m_nHourPointerSize = (int) ( 10*ScaleFactor);
			m_nMinutePointerSize = (int) ( 8*ScaleFactor);
			m_nSecondPointerSize = (int) ( 6*ScaleFactor);

			m_ptCenterPoint.X = (int)(sSize.Width/2);
			m_ptCenterPoint.Y = (int)(sSize.Width/2);

			this.m_sSize = sSize;
		}
/// <summary>
/// OverLoaded Paint function.
/// Here the Clock is Drawn
/// </summary>
/// <param name="pe"></param>
		protected override void OnPaint(PaintEventArgs pe)
		{

			//Let the Base class Paint
			base.OnPaint(pe);

			//Set the Offsets
            int offsetx = m_nOffset;
			int offsety = m_nOffset;

			//Copy the m_ptCenterPoint in centerPoint for use in this Function
			Point centerPoint = m_ptCenterPoint;
			//if the Boolean Back Image is true it draws the Back Image
			if (this.m_bBackImage)
				pe.Graphics.DrawImage(this.imgBackGround,0,0,ClientRectangle.Width,ClientRectangle.Height);

			//This for  Draws the perimeter Dots and Numbers
			for(int i=1;i<=60;i++)
			{
				//This is the Angle of the Current Number to Draw
                float NumberAngle =360-(360*(i/5)/12)+90;
				//Copy the NumberRadius for use in this function
				int NumberRadius = m_nNumberRadius;
				//Calculate the Pozition of the Number
                Point NumberPoint = GetPoint(centerPoint,NumberRadius,NumberAngle);

				//This is the Angle of the Current Dot
				float DotAngle =360-(360*(i)/60)+90;
				//Copy the Dot Radius for use in this function
				int DotRadius = (m_nClockRadius==0)?50:m_nClockRadius;
				//Calculate the Point of the Dot
				Point DotPoint = GetPoint(centerPoint,DotRadius,DotAngle);

				//Copy the DotSizes for use in this function
				int SmallDotSize = m_nSmallDotSize;
				int BigDotSize = m_nBigDotSize;
				
				//Draws the current small point
				pe.Graphics.FillEllipse(m_brPerimeterPoints,DotPoint.X-SmallDotSize/2,DotPoint.Y-SmallDotSize/2,SmallDotSize,SmallDotSize);

				//if it`s a big Dot
				if (i%5==0)
				{
					//if the Numbers are Visible Draw them at the calculated position
					if (m_bNumbers)
						pe.Graphics.DrawString((i/5).ToString(),m_ftNumbers,m_brNumbers,NumberPoint.X+m_nNumberOffset,NumberPoint.Y+m_nNumberOffset);
					//Draw the Big Dots
					pe.Graphics.FillEllipse(m_brPerimeterPoints,DotPoint.X-BigDotSize/2,DotPoint.Y-BigDotSize/2,BigDotSize,BigDotSize);
				}
			}	
			//Get the Current Local Time
			DateTime dt = DateTime.Now;

			//calculate the min value for use in the HourAngle
			float min = ((float)dt.Minute)/60;
			//Calculate the Angle of the Hour Pointer
			float HourAngle =360-(360*(dt.Hour+min)/12)+90;
			//Calculate the Angle of the Minute Pointer
			float MinuteAngle =360-(360*dt.Minute/60)+90;
			//Calculate the Angle of the Second Pointer
			float SecondAngle =360-(360*dt.Second/60)+90;
			
			//Calculate the EndPoint of the Hour Pointer
			Point HourEndPoint = GetPoint(centerPoint,m_nHourPointerLength,HourAngle);
			//Calculate the EndPoint of the Minute Pointer
			Point MinuteEndPoint = GetPoint(centerPoint,m_nMinutePointerLength,MinuteAngle);
			//Calculate the EndPoint of the Second Pointer
			Point SecondEndPoint = GetPoint(centerPoint,m_nSecondPointerLength,SecondAngle);

			//Copy the Sizes for use in this function
			int SecondSize = m_nSecondPointerSize;
			int MinuteSize = m_nMinutePointerSize;
			int HourSize   = m_nHourPointerSize;

			//Draw the Second Pointer Line
			pe.Graphics.DrawLine(new Pen(m_brSecondPointer,SecondSize),centerPoint,SecondEndPoint);
			//Draw the Second Pointer Top
			pe.Graphics.FillEllipse(m_brSecondPointer,SecondEndPoint.X-SecondSize/2,SecondEndPoint.Y-SecondSize/2,SecondSize,SecondSize);

			//Draw the Minute Pointer Line
			pe.Graphics.DrawLine(new Pen(m_brMinutePointer,MinuteSize),centerPoint,MinuteEndPoint);
			//Draw the Minute Pointer Top
			pe.Graphics.FillEllipse(m_brMinutePointer,MinuteEndPoint.X-MinuteSize/2,MinuteEndPoint.Y-MinuteSize/2,MinuteSize,MinuteSize);

			//Draw the Hour Pointer Line
			pe.Graphics.DrawLine(new Pen(m_brHourPointer,HourSize),centerPoint,HourEndPoint);
			//Draw the Hour Pointer Top
			pe.Graphics.FillEllipse(m_brHourPointer,HourEndPoint.X-HourSize/2,HourEndPoint.Y-HourSize/2,HourSize,HourSize);

			//The size of the Center Point
			int CenterPointSize = m_nHourPointerSize;
			//Draw the Center Point to cover the ends of the Pointers
			pe.Graphics.FillEllipse(Brushes.Black,centerPoint.X-CenterPointSize/2,centerPoint.Y-CenterPointSize/2,CenterPointSize,CenterPointSize);

			//if the Number Clock is Visible Draw It
			if (m_bNumberClock)
				pe.Graphics.DrawString(String.Format("{0:}:{1:}:{2:}",dt.Hour,dt.Minute,dt.Second),m_ftNumberClock,Brushes.Red,centerPoint.X-35*m_ftNumberClock.Size/12,centerPoint.Y+m_nNumberRadius + m_ftNumbers.Size+5);
		}
/// <summary>
/// This functions is used to calculate the endpoint given a Center Point ,a Radius and an angle
/// </summary>
/// <param name="ptCenter"></param>
/// <param name="nRadius"></param>
/// <param name="fAngle"></param>
/// <returns></returns>
		public Point GetPoint(Point ptCenter, int nRadius, float fAngle)
		{
			float x = (float)Math.Cos(2*Math.PI*fAngle/360)*nRadius+ptCenter.X;
			float y = -(float)Math.Sin(2*Math.PI*fAngle/360)*nRadius+ptCenter.Y;
			return new Point((int)x,(int)y);
		}

/// <summary>
/// These are the Clock Parameters
/// </summary>
		#region Clock Parameters

		public int m_nTimerInterval;

		public int TimerInterval
		{
			get
			{
				return m_nTimerInterval;
			}
			set
			{
				m_nTimerInterval = value;
				this.timer.Interval = value;
			}
		}

		public int m_nClockRadius;

		public int ClockRadius
		{
			get
			{
				return m_nClockRadius;
			}
			set
			{
				m_nClockRadius = value;
			}
		}

		public int m_nSmallDotSize;

		public int nSmallDotSize
		{
			get
			{
				return m_nSmallDotSize;
			}
			set
			{
				m_nSmallDotSize = value;
			}
		}

		public int m_nBigDotSize;

		public int nBigDotSize
		{
			get
			{
				return m_nBigDotSize;
			}
			set
			{
				m_nBigDotSize = value;
			}
		}

		public int m_nNumberOffset;

		public int nNumberOffset
		{
			get
			{
				return m_nNumberOffset;
			}
			set
			{
				m_nNumberOffset = value;
			}
		}

		public int m_nOffset;

		public int nOffset
		{
			get
			{
				return m_nOffset;
			}
			set
			{
				m_nOffset = value;
			}
		}

		public int m_nNumberRadius;

		public int nNumberRadius
		{
			get
			{
				return m_nNumberRadius;
			}
			set
			{
				m_nNumberRadius = value;
			}
		}

		public int m_nHourPointerLength;

		public int HourPointerLength
		{
			get
			{
				return m_nHourPointerLength;
			}
			set
			{
				m_nHourPointerLength = value;
			}
		}

		public int m_nMinutePointerLength;

		public int MinutePointerLength
		{
			get
			{
				return m_nMinutePointerLength;
			}
			set
			{
				m_nMinutePointerLength = value;
			}
		}

		public int m_nSecondPointerLength;

		public int SecondPointerLength
		{
			get
			{
				return m_nSecondPointerLength;
			}
			set
			{
				m_nSecondPointerLength = value;
			}
		}
        


		public int m_nHourPointerSize;

		public int HourPointerSize
		{
			get
			{
				return m_nHourPointerSize;
			}
			set
			{
				m_nHourPointerSize = value;
			}
		}

		public int m_nMinutePointerSize;

		public int MinutePointerSize
		{
			get
			{
				return m_nMinutePointerSize;
			}
			set
			{
				m_nMinutePointerSize = value;
			}
		}

		public int m_nSecondPointerSize;

		public int SecondPointerSize
		{
			get
			{
				return m_nSecondPointerSize;
			}
			set
			{
				m_nSecondPointerSize = value;
			}
		}

		
		public Size m_sSize;

		public Size sSize
		{
			get
			{
				return m_sSize;
			}
			set
			{
				m_sSize = value;
			}
		}


		public bool m_bNumbers;

		public bool bNumbers
		{
			get
			{
				return m_bNumbers;
			}
			set
			{
				m_bNumbers = value;
			}
		}
		public Brush m_brNumbers;

		public Brush brNumbers
		{
			get
			{
				return m_brNumbers;
			}
			set
			{
				m_brNumbers = value;
			}
		}

		public Font m_ftNumbers;

		public Font ftNumbers
		{
			get
			{
				return m_ftNumbers;
			}
			set
			{
				m_ftNumbers = value;
			}
		}
		public bool m_bNumberClock;

		public bool bNumberClock
		{
			get
			{
				return m_bNumberClock;
			}
			set
			{
				m_bNumberClock = value;
			}
		}

		public Font m_ftNumberClock;

		public Font ftNumberClock
		{
			get
			{
				return m_ftNumberClock;
			}
			set
			{
				m_ftNumberClock = value;
			}
		}

		public Point m_ptCenterPoint;

		public Point ptCenterPoint
		{
			get
			{
				return m_ptCenterPoint;
			}
			set
			{
				m_ptCenterPoint = value;
			}
		}


		public bool m_bBackImage;

		public bool bBackImage
		{
			get
			{
				return m_bBackImage;
			}
			set
			{
				m_bBackImage = value;
			}
		}

		public Image m_imgBackGround;

		public Image imgBackGround
		{
			get
			{
				return m_imgBackGround;
			}
			set
			{
				m_imgBackGround = value;
			}
		}

		public Brush m_brPerimeterPoints;

		public Brush brPerimeterPoints
		{
			get
			{
				return m_brPerimeterPoints;
			}
			set
			{
				m_brPerimeterPoints = value;
			}
		}

		public Brush m_brHourPointer;

		public Brush brHourPointer
		{
			get
			{
				return m_brHourPointer;
			}
			set
			{
				m_brHourPointer = value;
			}
		}

		public Brush m_brMinutePointer;

		public Brush brMinutePointer
		{
			get
			{
				return m_brMinutePointer;
			}
			set
			{
				m_brMinutePointer = value;
			}
		}

		public Brush m_brSecondPointer;

		public Brush brSecondPointer
		{
			get
			{
				return m_brSecondPointer;
			}
			set
			{
				m_brSecondPointer = value;
			}
		}
	
		#endregion
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Iulian Serban

Romania Romania
I am 18 years old and I have programmed for one year in C++ and MFC.
I am now programming in C# and .NET Framework.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.1411023.1 | Last Updated 10 Sep 2002
Article Copyright 2002 by Iulian Serban
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid