In the tutorial we are going to make a user control that is capable of display an analogue clock.
It it will be able to display a time static or display the current local time dynamically.
Lets BeginCreate a new Windows Form application, call it ClockApp
To ClockApp add a User Control call it UC_Clock
UC Standing for User ControlThe User ControlAdd to User control a timer.
Now view the code of the User Control, which will look like
vb
Public Class UC_Clock
End Class
To make the control useful we need to give it some properties.
PropertiesThese are the properties of the clock
vb
#Region "Properties of Clock"
#Region "Background Color"
Protected mBackground As Drawing.Color = Color.AntiqueWhite
< _
System.ComponentModel.Category("Clock Settings") _
, System.ComponentModel.DisplayName("Background Color") _
, System.ComponentModel.Description("Changes the background color of clock") _
> Public Property Background() As Drawing.Color
Get
Return mBackground
End Get
Set(ByVal value As Drawing.Color)
mBackground = value
MyBase.Refresh()
End Set
End Property
#End Region
Since this is the first property I'll explain whats going on.
Explanation of code section < _
System.ComponentModel.Category("Clock Settings") _
This places the property under the category
Clock Setting inside properties window of the Form Designer.
, System.ComponentModel.DisplayName("Background Color") _
This is the displayed name of the property.
, System.ComponentModel.Description("Changes the background color of clock") _
>This is the textual description of what the property does.
Public Property Background() As Drawing.ColorThis is property you can via code
eg
Me.UC_Clock1.Background=Color.Blue will set the background color to blue
vb
Get
Return mBackground
End Get
This gets the value of the protected member variable mBackground which is used to store what the color value of the background is.
vb
Set(ByVal value As Drawing.Color)
mBackground = value
MyBase.Refresh()
End Set
End Property
This sets the background color.
The
MyBase.Refrsesh causes the control to be redrawn with the new setting.
Back to the propertiesAdd the rest of the properties code
vb
#Region "Circle Color"
Protected mCircle As Drawing.Color = Color.Black
< _
System.ComponentModel.Category("Clock Settings") _
, System.ComponentModel.DisplayName("Circle Color") _
, System.ComponentModel.Description("Changes the color of the outer ring and Hour marks.") _
> Public Property Circle_Color() As Drawing.Color
Get
Return mCircle
End Get
Set(ByVal value As Drawing.Color)
mCircle = value
MyBase.Refresh()
End Set
End Property
#End Region
#Region "Hour Hand"
#Region "Colour"
Protected mColor_HourHand As Drawing.Color = Color.Black
< _
System.ComponentModel.Category("Clock Settings") _
, System.ComponentModel.DisplayName("Hour hand Color") _
, System.ComponentModel.Description("Change the color of the hour hand") _
> Public Property Hour_Color() As Drawing.Color
Get
Return mColor_HourHand
End Get
Set(ByVal value As Drawing.Color)
mColor_HourHand = value
MyBase.Refresh()
End Set
End Property
#End Region
#Region "Width"
Protected mWidth_HourHand As Single = 1.0
< _
System.ComponentModel.Category("Clock Settings") _
, System.ComponentModel.DisplayName("Hour hand Width") _
, System.ComponentModel.Description("Change the width of the hour hand") _
> Public Property HourWidth() As Single
Get
Return mWidth_HourHand
End Get
Set(ByVal value As Single)
If (value > 0) And (value < (Me.Width / 2)) Then
mWidth_HourHand = value
MyBase.Refresh()
End If
End Set
End Property
#End Region
#End Region
#Region "Minute Hand"
#Region "Color"
Protected mColor_MinuteHand As Drawing.Color = Color.Black
< _
System.ComponentModel.Category("Clock Settings") _
, System.ComponentModel.DisplayName("Minute Hand Color") _
, System.ComponentModel.Description("Change the color of the minute hand.") _
> Public Property Minute_Color() As Drawing.Color
Get
Return mColor_MinuteHand
End Get
Set(ByVal value As Drawing.Color)
mColor_MinuteHand = value
MyBase.Refresh()
End Set
End Property
#End Region
#Region "Width"
Protected mWidth_MinuteHand As Single = 1.0
< _
System.ComponentModel.Category("Clock Settings") _
, System.ComponentModel.DisplayName("Minute Hand Color") _
, System.ComponentModel.Description("Change the width of the minute hand.") _
> Public Property MinuteWidth() As Single
Get
Return mWidth_MinuteHand
End Get
Set(ByVal value As Single)
If (value > 0) And (value < (Me.Width / 2)) Then
mWidth_MinuteHand = value
MyBase.Refresh()
End If
End Set
End Property
#End Region
#End Region
#Region "Second Hand"
#Region "Color"
Protected mSecond As Drawing.Color = Color.Red
< _
System.ComponentModel.Category("Clock Settings") _
, System.ComponentModel.DisplayName("Second hand Color") _
, System.ComponentModel.Description("Change the color of the second hand") _
> Public Property Second_Color() As Drawing.Color
Get
Return mSecond
End Get
Set(ByVal value As Drawing.Color)
mSecond = value
MyBase.Refresh()
End Set
End Property
#End Region
#Region "Width"
Protected mSecondWidth As Single = 1.0
< _
System.ComponentModel.Category("Clock Settings") _
, System.ComponentModel.DisplayName("Second hand Width") _
, System.ComponentModel.Description("Change the width of the second hand.") _
> Public Property SecondWidth() As Single
Get
Return mSecondWidth
End Get
Set(ByVal value As Single)
If (value > 0) And (value < (Me.Width / 2)) Then
mSecondWidth = value
MyBase.Refresh()
End If
End Set
End Property
#End Region
#End Region
#Region "Face"
#Region "Color"
Protected mColor_Face As Drawing.Color = Color.White
< _
System.ComponentModel.Category("Clock Settings") _
, System.ComponentModel.DisplayName("Face Color") _
, System.ComponentModel.Description("Changes the color of clock face.") _
> Public Property Face_Color() As Drawing.Color
Get
Return mColor_Face
End Get
Set(ByVal value As Drawing.Color)
mColor_Face = value
MyBase.Refresh()
End Set
End Property
#End Region
Protected mCircleWidth As Single = 1.0
#End Region
#Region "Second hand visibility"
Protected mSecondsVisible As Boolean = True
<System.ComponentModel.Category("Clock Settings"), System.ComponentModel.DisplayName("Seconds Visibie")> Public Property SecondsVisible() As Boolean
Get
Return mSecondsVisible
End Get
Set(ByVal value As Boolean)
mSecondsVisible = value
MyBase.Refresh()
End Set
End Property
#End Region
#End Region
VariablesThese are all the shared variable of the clock control.
vb
#Region "Variables"
Protected mLocalTime As DateTime = Nothing ' This is used to store the time passed into control
Dim UsingLocalTime As Boolean = False 'This indicates if we are using the local time (dynamic)
Dim CirclePen As Pen
Dim MarkPen As Pen
Dim FaceBrush As SolidBrush
Dim WidthHalved As Single
Dim centreXY As Point
#End Region
ConstantsTheir are three (3) constants use by control
vb
#Region "Constants"
Public Const mAngle_H As Single = 360 / (12 * 60) 'Clock is divided into 12 60 minute sections
Public Const mAngle_M As Single = 360 / (60 * 60) 'Clock is divided into 60 60 second sections
Public Const mAngle_S As Single = 360 / 60 ' Clock is divided into 60 second sections
#End Region
Subroutines[i] you may get a few errors whilst typing the next section, don't worry they'll go once the control is finished.
vb
#Region "Procedures & Functions"
Private Sub Clock_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
DrawClock(e.Graphics)
End Sub
Public Sub ShowTimeOf(ByRef uselocal As Boolean, Optional ByRef iClockTime As DateTime = Nothing)
' This routine set the time displayed on the clock
If uselocal Then
' start the timer & indicate were using local live time
MyClass.Timer1.Start()
UsingLocalTime = True
Else
' Stop the timer & indicate weren't using local live time
MyClass.Timer1.Stop()
UsingLocalTime = False
' set the clock the required time
mLocalTime = iClockTime
End If
' Redraw the clock
Me.Refresh()
End Sub
Public Sub DrawClock(ByRef g As Graphics)
' This is routine that draw the clock, hands and all
CirclePen = New Pen(mCircle, mCircleWidth)
MarkPen = New Pen(mCircle, mCircleWidth * 2)
FaceBrush = New SolidBrush(mColor_Face)
' Define the centre of the control
WidthHalved = ((Me.Width - CirclePen.Width) / 2)
centreXY = New Point(WidthHalved, WidthHalved)
' Draw the face of the clock
DrawFace(g)
If UsingLocalTime Then
' Draw the clock hands for live local time
DrawHands(g, Now)
Else
' Draw the clock hands for stored time
DrawHands(g, mLocalTime)
End If
End Sub
Private Sub DrawHands(ByRef g As Graphics, ByRef showtime As DateTime)
' This the does the complex task of drawing the hands
' Set the length of the various arms
Dim HourArmLength As Single = WidthHalved * 0.6
Dim MinuteArmLength As Single = WidthHalved * 0.95
Dim SecondArmLength As Single = WidthHalved * 0.65
' Create pens for hands
Dim HourPen As New Pen(mColor_HourHand, mWidth_HourHand)
Dim MinutePen As New Pen(mColor_MinuteHand, mWidth_MinuteHand)
Dim SecondPen As New Pen(mSecond, mSecondWidth)
' Calculate the angles of hands in degrees
Dim Degrees_Hour As Single = mAngle_H * (((showtime.Hour Mod 12) * 60) + showtime.Minute) 'Using Modulo 12 in case of 24hr setting
Dim Degress_Minute As Single = mAngle_M * ((showtime.Minute * 60) + showtime.Second)
Dim Degress_Seconds As Single = mAngle_S * showtime.Second
' Work out were the end of the hands are, from the centre of the control
Dim HourXY As New Point((centreXY.X) + HourArmLength * Math.Sin(DegreeToRadians(Degrees_Hour)), centreXY.Y - HourArmLength * Math.Cos(DegreeToRadians(Degrees_Hour)))
Dim MinuteXY As New Point((centreXY.X) + MinuteArmLength * Math.Sin(DegreeToRadians(Degress_Minute)), centreXY.Y - MinuteArmLength * Math.Cos(DegreeToRadians(Degress_Minute)))
Dim SecondXY As New Point((centreXY.X) + SecondArmLength * Math.Sin(DegreeToRadians(Degress_Seconds)), centreXY.Y - SecondArmLength * Math.Cos(DegreeToRadians(Degress_Seconds)))
' Draw Hour hand
g.DrawLine(HourPen, centreXY, HourXY)
' Draw Minute Hand
g.DrawLine(MinutePen, centreXY, MinuteXY)
' Draw Second Hand
If SecondsVisible Then g.DrawLine(SecondPen, centreXY, SecondXY)
' Tidy up Pens & Brushes
SecondPen.Dispose()
MinutePen.Dispose()
HourPen.Dispose()
End Sub
Private Sub DrawFace(ByRef g As Graphics)
' This Routine draw the clock face
' Clear the clock to the color of the background
g.Clear(mBackground)
' Draw Face Circle
g.FillEllipse(FaceBrush, 0, 0, Me.Width - CirclePen.Width, Me.Height - CirclePen.Width)
' Draw Outer Ring
g.DrawEllipse(CirclePen, 0, 0, Me.Width - CirclePen.Width, Me.Height - CirclePen.Width)
' Draw the hour marks
Dim si As Single
Dim ci As Single
For i As Integer = 0 To 11
si = Math.Sin(DegreeToRadians(30 * i))
ci = Math.Cos(DegreeToRadians(30 * i))
g.DrawLine(IIf((i Mod 3) = 0, MarkPen, CirclePen), _
CInt(centreXY.X + WidthHalved * si), _
CInt(centreXY.Y - WidthHalved * ci), _
CInt(centreXY.X + (WidthHalved * IIf((i Mod 3) = 0, 0.8, 0.9)) * si), _
CInt(centreXY.Y - (WidthHalved * IIf((i Mod 3) = 0, 0.8, 0.9)) * ci))
Next
End Sub
Private Sub Clock_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' Me.Timer1.Start()
' Me.Refresh()
ShowTimeOf(False)
End Sub
Private Sub Clock_SizeChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.SizeChanged
' If the clock isn't square, make it square
If Me.Height <> Me.Width Then Me.Height = Me.Width
End Sub
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
MyClass.Refresh()
End Sub
#End Region
Useful functionsvb
#Region "Misc. Useful Functions"
' Convert Radians To Degree
Private Shared Function RadiansToDegree(ByVal radian As Double) As Double
Return (180 / Math.PI) * radian
End Function
' Convert Degree to Radians
Private Shared Function DegreeToRadians(ByVal degree As Double) As Double
Return (Math.PI / 180) * degree
End Function
#End Region
Add thats it for the Clock control
Now to test the Control out lets make a form with four clocks on it with varied parameters.
Test FormDrag 4(Four) UC_Clock controls on to form1 and then view the code of Form1.
Insert the followinfg code, which demonstrates the results various examples of the parameters the can be passed in to ShowTimeOf method.
vb
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Me.UC_Clock1.ShowTimeOf(True, New DateTime(2008, 7, 23, 9, 30, 15))
Me.UC_Clock2.ShowTimeOf(True)
Me.UC_Clock3.ShowTimeOf(False)
Me.UC_Clock4.ShowTimeOf(False, New DateTime(2008, 7, 23, 9, 30, 15))
End Sub
End Class
Run