Building an Analog Clock in Visual Basic

Introduction

One of my very first memories of starting out as a developer was that I once received code in C++ from one of my dad's friends. This code was to create an analog clock (you know, the old round ones without digital numbers). It looked beautiful, but I did not understand any of the code. There and then, I decided that I wanted to be a decent enough developer to be able to to this one day.

With today's article, I will demonstrate how to create an analog clock in VB.

Drawing in VB

I have always had a fascination with the Drawing namespaces in VB. Here are a few articles covering various drawing options in VB.

Okay, I am sorry.... You need some math....

The good news is that I used to suck at math, mainly due to teachers not showing any interest in helping me. This was a long time ago when I was actually forced to take math. Yep, I was forced. I initially studied four different languages in high school, due to the subjects not being popular enough.

This caused me to be two whole semesters behind in math and economics and no one wanted to help me catch up. Luckily, I figured everything out on my own. If my math teachers could see me today....

Anyway, all you need to know is the following:

Our Project

There is no design needed, just a simple Windows Forms project with an empty form. We will create the needed controls dynamically.

Code

Import the Drawing Namespace:

Imports System.Drawing.Drawing2D

Declare your variables:

   Const Convert As Double = Math.PI / 180

   Const SecRadius As Double = 185
   Const MinRadius As Double = 180
   Const HrRadius As Double = 155

   Dim SecAngle As Double
   Dim MinAngle As Double
   Dim HrAngle As Double

   Dim SecX As Single = 220
   Dim SecY As Single = 20
   Dim MinX As Single = 220
   Dim MinY As Single = 20
   Dim HrX As Single = 220
   Dim HrY As Single = 20

   Dim hrs, min, value As Integer
   Dim TimeString As String

   Dim WithEvents tmrClock As New Timer

   Dim WithEvents lblPanel As New Label
   Dim lblTB As New Label

   Dim StartPoint(60) As PointF
   Dim EndPoint(60) As PointF
   Dim NumberPoint() As PointF = {New PointF(285, 50),
      New PointF(350, 115), New PointF(376, 203),
      New PointF(350, 290), New PointF(285, 350),
      New PointF(205, 366), New PointF(125, 350),
      New PointF(60, 290), New PointF(38, 203),
      New PointF(55, 120), New PointF(112, 59),
      New PointF(196, 36)}
   'Create the Pens
   Dim GreenPen As Pen = New Pen(Color.Green, 4)
   Dim BluePen As Pen = New Pen(Color.Blue, 4)
   Dim OrangePen As Pen = New Pen(Color.DarkOrange, 5)
   Dim BlackPen As Pen = New Pen(Color.Black, 6)
   Dim myPen As New Pen(Color.DarkBlue, 8)
   'Create the Fonts
   Dim NumberFont As New Font("Arial", 25, FontStyle.Bold)
   Dim ClockFont As New Font("Arial", 18, FontStyle.Bold)

   'Create the Bitmap to draw the clock face
   Dim ClockFace As New Bitmap(445, 445)
   Dim gr As Graphics = Graphics.FromImage(ClockFace)

Add the following two events to set up the drawing operations:

   Private Sub Form1_Load(ByVal sender As System.Object, _
      ByVal e As System.EventArgs) Handles MyBase.Load

      BluePen.SetLineCap(LineCap.Round, LineCap.ArrowAnchor, _
         DashCap.Flat)
      OrangePen.SetLineCap(LineCap.Round, LineCap.ArrowAnchor, _
         DashCap.Flat)
      BlackPen.SetLineCap(LineCap.Round, LineCap.ArrowAnchor, _
         DashCap.Flat)
      DoubleBuffered = True
      Me.Size = New Size(570, 470)
      Me.FormBorderStyle = Windows.Forms.FormBorderStyle.None
      Me.TransparencyKey = SystemColors.Control
      Me.CenterToScreen()
      CalculatePerimeter()
      DrawFace()
      tmrClock.Interval = 990
      tmrClock.Start()
   End Sub

   Protected Overrides Sub OnPaint(ByVal e As _
         System.Windows.Forms.PaintEventArgs)
      e.Graphics.SmoothingMode = SmoothingMode.HighQuality
      'Draw Clock Background
      e.Graphics.DrawImage(ClockFace, Point.Empty)
      'Draw Digital Time
      e.Graphics.DrawString(TimeString, ClockFont, _
         Brushes.White, 170, 260)
      'Draw Hands
      e.Graphics.DrawLine(BlackPen, 220, 220, HrX, HrY)
      e.Graphics.FillEllipse(Brushes.Black, 210, 210, 20, 20)
      e.Graphics.DrawLine(OrangePen, 220, 220, MinX, MinY)
      e.Graphics.FillEllipse(Brushes.DarkOrange, 212, 212, 16, 16)
      e.Graphics.DrawLine(BluePen, 220, 220, SecX, SecY)
      e.Graphics.FillEllipse(Brushes.Blue, 215, 215, 10, 10)
   End Sub

Add the DrawFace Sub that is responsible for the drawing the clock's face:

   Sub DrawFace()
      gr.SmoothingMode = SmoothingMode.HighQuality
      'Draw Clock Background
      gr.FillEllipse(Brushes.Beige, 20, 20, 400, 400)
      gr.DrawEllipse(GreenPen, 20, 20, 400, 400)
      gr.DrawEllipse(Pens.Red, 120, 120, 200, 200)
      'Draw Increments around cicumferance
      For I As Integer = 1 To 60
         gr.DrawLine(GreenPen, StartPoint(I), _
            EndPoint(I))
      Next
      'Draw Numbers
      For I As Integer = 1 To 12
         gr.DrawString(I.ToString, NumberFont, _
            Brushes.Black, NumberPoint(I - 1))
      Next

      'Draw Digital Clock Background
      gr.FillRectangle(Brushes.DarkBlue, _
         170, 260, 100, 30)
      myPen.LineJoin = LineJoin.Round
      gr.DrawRectangle(myPen, 170, 260, 100, 30)
   End Sub

Add the CaclulatePerimter Sub:

   Sub CalculatePerimeter()
      Dim X, Y As Integer
      Dim radius As Integer
      For I As Integer = 1 To 60
         If I Mod 5 = 0 Then
            radius = 182
         Else
            radius = 190
         End If
         'Calculate Start Point
         X = CInt(radius * Math.Cos((90 - I * 6) * _
            Convert)) + 220
         Y = 220 - CInt(radius * Math.Sin((90 - I * 6) * _
            Convert))
         StartPoint(I) = New PointF(X, Y)
         'Calculate End Point
         X = CInt(200 * Math.Cos((90 - I * 6) * _
            Convert)) + 220
         Y = 220 - CInt(200 * Math.Sin((90 - I * 6) * _
            Convert))
         EndPoint(I) = New PointF(X, Y)
      Next
   End Sub

Finally, to make it all work, add the Timer's tick event:

   Private Sub tmrClock_Tick(ByVal sender As System.Object, _
         ByVal e As System.EventArgs) Handles tmrClock.Tick
      TimeString = Now.ToString("HH:mm:ss")
      'Set The Angle of the Second, Minute and Hour hand
      'according to the time
      SecAngle = (Now.Second * 6)
      MinAngle = (Now.Minute + Now.Second / 60) * 6
      HrAngle = (Now.Hour + Now.Minute / 60) * 30
      'Get the X,Y co-ordinates of the end point of each hand
      SecX = CInt(SecRadius * Math.Cos((90 - SecAngle) * _
         Convert)) + 220
      SecY = 220 - CInt(SecRadius * Math.Sin((90 - SecAngle) * _
         Convert))
      MinX = CInt(MinRadius * Math.Cos((90 - MinAngle) * _
         Convert)) + 220
      MinY = 220 - CInt(MinRadius * Math.Sin((90 - MinAngle) * _
         Convert))
      HrX = CInt(HrRadius * Math.Cos((90 - HrAngle) * _
         Convert)) + 220
      HrY = 220 - CInt(HrRadius * Math.Sin((90 - HrAngle) * _
         Convert))
      Refresh()
   End Sub

Conclusion

Graphics can be quite fun, once you get the hang of them. I am including a working sample with this article. Happy drawing!



About the Author

Hannes DuPreez

Hannes du Preez is a Microsoft MVP for Visual Basic for the ninth consecutive year. He loves technology and loves Visual Basic. He loves writing articles and proving that Visual Basic is more powerful than what most believe. His ultimate dream is to write a Visual Basic book, hopefully one day that dream will come true. You are most welcome to reach him at: ojdupreez1978@gmail.com

Related Articles

Downloads

Comments

  • Code error?

    Posted by Chas Large on 09/30/2016 04:21am

    Hi Hannes, Thanks for the code, just what I was looking for. I'm writing a weather station app and wanted to draw a compass for Wind Direction so this will be a good start for me. However, when I added the code to VS2015 it came up with an error for the code in line 12 of the form load:- Me.FormBorderStyle = Windows.Forms.FormBorderStyle.None Changing this to:- Me.FormBorderStyle = FormBorderStyle.None Fixes the problem. Hope this helps others. Thanks again. Chas.

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date