Click here to Skip to main content
14,738,277 members
Articles » Desktop Development » Desktop Gadgets » General
Posted 14 Mar 2009


56 bookmarked

An Analog Clock Control

Rate me:
Please Sign up or sign in to vote.
4.76/5 (21 votes)
14 Mar 2009LGPL3
An analog clock control with timezone modification
Analog Clock Control


This is my second article for The Code Project community. This article will explain about making an analog clock control that mimics Windows Vista clock sidebar gadget. It mimics the loading and tick effect, has timezone property which can be used to maintain timezone for displaying in the clock, and has a nice designer support feature as well.

TheClock is an analog clock control that mimics Windows Vista sidebar gadget especially in its behaviour like loading, ticks, and even timezones. Take a note that since timezone features will have a complex method, I will separate the article which you can find after I have finished with this article.


With the release of Windows Vista, most people would know that one new thing that comes with it is the sidebar with gadgets. In all those gadgets, there's a control that catches my attention, the analog clock. It has nice features and interface. After observing how it works, I decided to make my own VB analog clock based on that gadget. Thus, I created this article to share with CodeProject members, especially most of members who already contributed their good articles to this site that helped me a lot with my work.

Using the Code

The control has a main component named TheClock. The main objective that this component must have is its ability to tick in a fancy way, just like Windows Vista gadget. The second feature that it should have is Timezone feature. This article will explain about the main component itself. I will discuss Timezone feature separately in another article.

Initialize the Component

The first thing we need to do is to make a component. TheClock will inherit control object and will implement ISupportInitialize because we will add some initial values after placing the control.

#Region "The Clock - Copyright (C) 2007 Michael Rawi"
'The Clock
'Windows Forms Component - NET Framework 2.0
'Copyright (C) 2007 Michael Rawi

'This library is free software; you can redistribute it and/or
'modify it under the terms of the GNU Lesser General Public
'License as published by the Free Software Foundation; either
'version 2.1 of the License, or (at your option) any later version.

'This library is distributed in the hope that it will be useful,
'but WITHOUT ANY WARRANTY; without even the implied warranty of
'Lesser General Public License for more details.

'Michael Rawi
#End Region
Imports System.DateTime

''' <summary>
''' An analog clock.
''' </summary>
''' <remarks>Created by Michael Rawi</remarks>
<Designer(GetType(TheClockDesigner)), _
Description("A modern analog clock."), _
ToolboxBitmap(GetType(TheClock), "TheClock.png")> _
Public Class TheClock
    Inherits Control
    Implements System.ComponentModel.ISupportInitialize


End Class

Setting up Variables and Properties

Before making a control, you should have known what variable you will need for developing the control. You don't have to know completely since you can have additional variables later, but you should at least define what you will need the most. For this control, we will also need enumerations.


#Region "Enumeration"
    Public Enum Styles
        Analog = 0
    End Enum

    Public Enum SecondTicks
        [Default] = 0
        Rapid = 1
        Original = 2
    End Enum

    Private Enum FadeStatus
        [In] = 0 'Slowly disappeared - 1.0F~0.5F in 0.5 second by 5 Frame
        Out = 1 'Slowly reappeared
    End Enum
#End Region

#Region "Component Variables"
 Region "Core Variables"
    Private WithEvents _tmrTime As Timer
    Private WithEvents _tmrTick As Timer
    Private WithEvents _tmrLoad As Timer

    Private _imgS As Image
    Private _imgM As Image
    Private _imgH As Image

    Private _angleS As Single
    Private _angleM As Single
    Private _angleH As Single

    Private _ComInfo As New Devices.ComputerInfo
#End Region
#Region "Private Properties"
    Private _secTick As SecondTicks = SecondTicks.Default
    Private _style As Styles
#End Region
#Region "Load Animation"
    Private _loadTimeframe As Single
    Private _loadHAngle As Single
    Private _loadMAngle As Single
    Private _loadSAngle As Single
    Private _loadMod As Integer
#End Region
#Region "Features"
    Private _ShowSecond As Boolean = True
    Private _AdvancedMode As Boolean = False

    Private _FadeFocus As Boolean = True
    Private _FadeStatus As FadeStatus = FadeStatus.Out
    Private _FadeAlpha As Single = 0.5F
    Private WithEvents _tmrFade As Timer

    Private _span As TimeSpan = New TimeSpan(0, 0, 0)
    Private _State As String
#End Region
#End Region


In the next step, we will create some property value for making design time easier.


#Region "Properties"
    ''' <summary>
    ''' Get or set the style of the clock.
    ''' </summary>
    ''' <value>Style</value>
    ''' <returns>Current Style</returns>
    ''' <remarks></remarks>
    <Description("Get or set the style of the Clock"), Category("Features"), _
    DefaultValue(GetType(Styles), "Analog")> _
    Public Property Style() As Styles
            Return _style
        End Get
        Set(ByVal value As Styles)
            _style = value
        End Set
    End Property

    ''' <summary>
    ''' Get or set the second tick's style.
    ''' </summary>
    ''' <value>SecondTick</value>
    ''' <returns>Current SecondTicks</returns>
    ''' <remarks></remarks>
    <Description("Get or set the second tick's style"), Category("Features"), _
    DefaultValue(GetType(SecondTicks), "Default")> _
    Public Property SecondTick() As SecondTicks
            Return _secTick
        End Get
        Set(ByVal value As SecondTicks)
            _secTick = value
            Select Case value
                Case SecondTicks.Rapid
                    _tmrTime.Interval = 100
                Case Else
                    _tmrTime.Interval = 1000
            End Select
        End Set
    End Property

    ''' <summary>
    ''' Get or set the second visibility.
    ''' </summary>
    ''' <value>Boolean</value>
    ''' <returns>Second visibility</returns>
    ''' <remarks></remarks>
    <Description("Get or set the second visibility"), Category("Features"), _
    DefaultValue(True)> _
    Public Property ShowSecond() As Boolean
            Return _ShowSecond
        End Get
        Set(ByVal value As Boolean)
            _ShowSecond = value
        End Set
    End Property

    ''' <summary>
    ''' Enable advanced mode. This feature is not ready yet
    ''' </summary>
    ''' <value>Boolean</value>
    ''' <returns>AdvancedMode</returns>
    ''' <remarks></remarks>
    <Browsable(False)> _
    Public Property AdvancedMode() As Boolean
            Return _AdvancedMode
        End Get
        Set(ByVal value As Boolean)
            _AdvancedMode = value
        End Set
    End Property

    ''' <summary>
    ''' Enable fade focus effect.
    ''' </summary>
    ''' <value>Boolean</value>
    ''' <returns>Current fadefocus effect</returns>
    ''' <remarks></remarks>
    <Description("Enable fade focus effect"), Category("Features"), _
    DefaultValue(True)> _
    Public Property EnableFadeFocus() As Boolean
            Return _FadeFocus
        End Get
        Set(ByVal value As Boolean)
            _FadeFocus = value
        End Set
    End Property

    ''' <summary>
    ''' Set clock time span against current time.
    ''' </summary>
    ''' <value>Timespan</value>
    ''' <returns>Current timespan</returns>
    ''' <remarks></remarks>
    <Description("Set clock time span against current time"), Category("Features"), _
    DefaultValue(GetType(TimeSpan), "00:00:00")> _
    Public Property ClockSpan() As TimeSpan
            Return _span
        End Get
        Set(ByVal value As TimeSpan)
            _span = value
        End Set
    End Property
#End Region


The one important thing to do is to lock the size of the control, since we will have fixed size from the background image. This can be done with override OnSizeChanged event.

Making the Stuff Work

After the initialize step, now we will continue with the main feature. Region Draw Surface Area contains a method that is needed for drawing Hour, Minute and Second hand. To create all the effects, we will have 3 timers for this control. The first timer will act as time indicator. It will tick each second and tell the control to update the second hand's position. The second timer will do the "bounce" effect. Now, if you observe the Windows gadget correctly, you will notice that after the second hand tick, it will bounce back a little, just like the real clock. In order to create that effect, we will need a timer to bounce the second hand after it ticks. The last timer will be used for the initialize process. After the control loads, it needs to find the position of the current time and place the hands in the right place in an elegant way. That's why we need to implement ISupportInitialize to do the work.


Public Sub EndInit() Implements System.ComponentModel.ISupportInitialize.EndInit
    'Activate the clock
    If Not Me.DesignMode Then
        If ((Now.Hour + _span.Hours) Mod 12) * _
		30 > (Now.Minute + _span.Minutes) * 6 Then
            _loadMod = 1
            _loadMod = 3
        End If
        _loadTimeframe = (Now.Minute + _span.Minutes) * 6 + (Now.Second \ 10)
        _loadHAngle = (((Now.Hour + _span.Hours) Mod 12) * _
	    30 + ((Now.Minute + _span.Minutes) * 6 \ 12)) / (_loadTimeframe / 6)
        _loadMAngle = 6

        _tmrLoad = New Timer
        _tmrLoad.Interval = 50
        _angleH = 0
        _angleM = 0
        _angleS = 0
    End If
End Sub


Adding Designer Support

Designer Support

A good component should have some features that make development time easier. One of the features is designer support. This will making our component easier to use.

	(System.Security.Permissions.SecurityAction.Demand, Name:="FullTrust")> _
Public Class TheClockDesigner
    Inherits System.Windows.Forms.Design.ControlDesigner

    Private lists As DesignerActionListCollection

    Public Overrides ReadOnly Property ActionLists() _
            As DesignerActionListCollection
            If lists Is Nothing Then
                lists = New DesignerActionListCollection()
                lists.Add( _
                New TheClockActionList(Me.Component))
            End If
            Return lists
        End Get
    End Property
End Class

Timezone Support

Timezone support

Use own time

For the last feature, we will add Timezone support for the component. By adding this feature, the user can choose what time she/he needs for the control instead of just following Windows standard control. This feature can also be integrated with designer support to make it even easier to use. Moreover, it will have some nice "Use My Own" feature that can adjust the clock time difference with input from the user.

Points of Interest

There's one problem still bothering me while creating this control. For a strange reason, I must adjust the second hand position determined by XP or Vista OS. I currently tested my project on those OSs, and find that I need to move the second hand 1 pixel to the left if I use XP OS. This code can be found in the DrawSecondHand method. Until now, it is still confusing for me to know that XP coordinate is slightly different from Vista coordinates.

Private Sub DrawSecondHand(ByVal g As Graphics, ByVal Angle As Single)
    Dim container As Rectangle
    If Angle <> 180 Then
        container = New Rectangle(-6, -64, 13, 129)
        If _ComInfo.OSVersion.StartsWith("5.1") Then
            container = New Rectangle(-7, -65, 13, 129) 'This works on XP
            container = New Rectangle(-6, -64, 13, 129) 'This works on Vista
        End If
    End If

    g.TranslateTransform(64.0F, 65.0F)
    If _FadeFocus Then
        Using ia As New Imaging.ImageAttributes
            Dim cm As New Imaging.ColorMatrix

            cm.Matrix33 = _FadeAlpha
            g.DrawImage(_imgS, container, 0, 0, 13, 129, _
                GraphicsUnit.Pixel, ia)
        End Using
        g.DrawImage(_imgS, container)
    End If
    'g.DrawImage(_imgS, container)
End Sub


  • Version 1.0 - Initial release


This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)


About the Author

Team Leader Component Crafts
Indonesia Indonesia
Got his BA in Information and Technology from University of Surabaya, Indonesia in 2004. Finished his post graduate at Magistrate and Management Institute of Technology, Surabaya in 2009.

He has developed several middle to large scale enterprise application, mostly on windows based architecture.

Currently working as IT Manager on a company based on Sidoarjo.

Comments and Discussions

GeneralError in TimeZoneConvert function when timezone's DisplayName="Universal Time (GMT)". Pin
malac123-Nov-10 19:35
Membermalac123-Nov-10 19:35 
GeneralConvert to C# Pin
haazeq3-Sep-10 3:51
Memberhaazeq3-Sep-10 3:51 
GeneralRe: Convert to C# Pin
Michael Rawi4-May-11 5:45
MemberMichael Rawi4-May-11 5:45 
Generalmy 5 Pin
VirtualVoid.NET24-Apr-10 23:13
MemberVirtualVoid.NET24-Apr-10 23:13 
... but unfortunately I don't have VB.NET installed in my IDE Smile | :) )

GeneralRe: my 5 Pin
Michael Rawi4-May-11 5:43
MemberMichael Rawi4-May-11 5:43 
GeneralGood one Pin
NarendraSinghJTV24-Nov-09 20:01
MemberNarendraSinghJTV24-Nov-09 20:01 
GeneralRe: Good one Pin
Michael Rawi4-May-11 5:43
MemberMichael Rawi4-May-11 5:43 
General5/5 Pin
VCSKicks27-Mar-09 18:57
MemberVCSKicks27-Mar-09 18:57 
GeneralRe: 5/5 Pin
Michael Rawi28-Apr-09 17:20
MemberMichael Rawi28-Apr-09 17:20 
QuestionWrong TIME Pin
GeneralBiSoN20-Mar-09 4:50
MemberGeneralBiSoN20-Mar-09 4:50 
AnswerRe: Wrong TIME Pin
Michael Rawi28-Apr-09 17:19
MemberMichael Rawi28-Apr-09 17:19 
GeneralMy Vote of 5 Pin
sam.hill14-Mar-09 6:35
Membersam.hill14-Mar-09 6:35 
GeneralRe: My Vote of 5 Pin
Michael Rawi28-Apr-09 17:20
MemberMichael Rawi28-Apr-09 17:20 
Generalmy vote of 4 Pin
Adrian Pasik14-Mar-09 5:59
MemberAdrian Pasik14-Mar-09 5:59 
GeneralRe: my vote of 4 Pin
Michael Rawi28-Apr-09 17:21
MemberMichael Rawi28-Apr-09 17:21 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.