Click here to Skip to main content
15,861,168 members
Articles / Programming Languages / Visual Basic
Article

Working analog clock with textures

Rate me:
Please Sign up or sign in to vote.
4.00/5 (12 votes)
7 Jan 20044 min read 117K   674   27   17
Step by step instructions on how to use the new translate features.

Sample Image - clock_picture.gif

Introduction

We are going to be taking a look at the construction of an analog clock using textured backgrounds. I know this "looks" hard and intimidating, but believe me, it's anything but hard :-)

Step 1

Modifying your form's startup

First thing is, we need to change the way your form starts so we can control the loading procedure. This is fairly simple to accomplish. What you need to do is create a Shared Sub Main in your main program and set that as the startup. Don't forget to name your form frmClock.

VB.NET
Shared Sub Main()
    Application.Run(New frmClock())
    Application.Exit()
End Sub

This will start up the form named frmClock. Then, when it's done, exit the application. Now, we need to modify the new procedure for the form and insert a me.show command and an initClock command.

VB.NET
Public Sub New()
    MyBase.New()
    InitializeComponent()
    initclock()
End Sub

All that's left to do now is change the project's startup properties to make it use our Shared sub Main and not the standard startup procedure. Go to Solution Explorer and right click on your project's properties and change the Startup Object.

Step 2

Create the cHands class to hold the hands information

VB.NET
01:    Public Class cHands
02:    Private Angle As Integer = 0
03:    Public Path As New Drawing2D.GraphicsPath()
04:    Public filled As Boolean = False
05:
06:
07:    ' We have to set a new angle so subtract it from the old one and thats 
08:    ' how far we have to move
09:    '
10:    Public Sub setAngle(ByVal newAngle As Integer, ByVal imgCenter As PointF)
11:        Dim Rotate As Integer = newAngle - Angle
12:        Dim trans As New Drawing2D.Matrix()
13:        trans.RotateAt(Rotate, imgCenter)
14:        Path.Transform(trans)
15:        Me.Angle = newAngle
16:    End Sub
17:
18:
19:    ' Did somone say draw?
20:    '
21:    Public Sub draw(ByVal imgDraw As Graphics)
22:        If filled Then
23:            imgDraw.FillPath(Brushes.DimGray, Path)
24:            imgDraw.DrawPath(Pens.Black, Path)
25:        Else
26:            imgDraw.DrawPath(New Pen(Color.DimGray, 2), Path)
27:        End If
28:    End Sub
29: End Class
Line 1
Declare the class name.
Lines 2-4
Set up some internal variables, one to track the last angle, one to hold the graphics object and another to hold the value if we want to fill the lines.
 
Line 10
Create Sub setAngle that will take the new angle of the hand minus the old angle on the hand and rotate the object the rest of the distance.
Line 11
Figure out how much farther the line needs to rotate to get to where it needs to be.
Line 12
Create a new Transform Matrix object.
Lines 13-14
Rotate the hand the distance it needs to go and set the pivot point (rotation point) at the center of the circle.
Line 15
Set the old angle to the new angle.
Line 16
End Sub
 
Line 21
Create Sub Draw that will draw your paths.
Line 22-25
If you want the hands filled, fill them in and draw a black border around them to look nice.
Lines 26-27
Draw the line with a thickness of two, but don't fill it in.
Line 28
End Sub.

In this step, we have created a class that will be used to store information about the individual hands of the clock.

Step 3

Controls

Go to your form, add a Timer and a PictureBox control. Set the PictureBox to the name clock with a background color of black and set it as docked with the entire form. Leave the Timer control as timer1 and enable it.

Step 4

Tick tock goes the clock

First thing we need to do is create the variables for the clock hands using our cHands class and a point that will denote the center of the screen.

VB.NET
Private handHour As New cHands()
Private handMinute As New cHands()
Private handSecond As New cHands()
Private center = New PointF(150, 150)

Next is the part where it all starts, the initclock Sub.

VB.NET
Private Sub initclock()
    Me.ClientSize = New Size(300, 300)

First things first, make sure the client area for the form is 300 x 300. Now, we initialize the hands, remember the Path object in cHands? Well, it's come time to set it, but first a few notes. We will always set the hand straight up (at the 12:00 position). From here, it will be rotated from the center of the screen, so it will look as if it is turning like a real clock. We draw our lines with points, point a connects to point b, point b connects to point c, and point c connects again with point a. These points are contained within an array of points. This can look quite overwhelming but really makes perfect sense if you step through it slowly.

VB.NET
Dim drawHour As Point() = _
    {New Point(Int(clock.Width / 2), Int(clock.Height / 2)), _
    New Point(Int(clock.Width / 2 - 5), 80), _
    New Point(Int(clock.Width / 2), 50), _
    New Point(Int(clock.Width / 2 + 5), 80), _
    New Point(Int(clock.Width / 2), Int(clock.Height / 2))}

Dim drawMinute As Point() = _
   {New Point(Int(clock.Width / 2), Int(clock.Height / 2)), _
    New Point(Int(clock.Width / 2 - 5), 60), _
    New Point(Int(clock.Width / 2), 30), _
    New Point(Int(clock.Width / 2 + 5), 60), _
    New Point(Int(clock.Width / 2), Int(clock.Height / 2))}

Why didn't we use center instead of New Point(Int(clock.Width / 2), Int(clock.Height / 2))? Well, center is a PointF (Floating point or Single) and this requires a point (integer). Now we have to associate these values with the Path object.

VB.NET
handHour.Path.AddLines(drawHour)
handHour.filled = True

handMinute.Path.AddLines(drawMinute)
handMinute.filled = True

But wait, what about the second hand? Well, the second hand is just a line. It's not a shape that needs to be filled. So, it's really easy to draw.

VB.NET
    handSecond.Path.AddLine(center, New PointF(Int(clock.Width / 2), 25))
End Sub

That's it for this Sub. Now, on to the clock timer (its really complicated :-)).

VB.NET
Private Sub Timer1_Tick(ByVal sender As System.Object, _
             ByVal e As System.EventArgs) Handles Timer1.Tick
    clock.Invalidate()
End Sub

Basically, what this says is every time the timer ticks, repaint the clock. Now we need to create the painting event for clock.

VB.NET
Private Sub clock_Paint(ByVal sender As Object, _
      ByVal e As System.Windows.Forms.PaintEventArgs) Handles clock.Paint
    handHour.setAngle((360 / 60) * Val(Format(Now, "hh")), center)
    handMinute.setAngle((360 / 60) * Val(Format(Now, "mm")), center)
    handSecond.setAngle((360 / 60) * Val(Format(Now, "ss")), center)

    handHour.draw(e.graphics)
    handMinute.draw(e.graphics)
    handSecond.draw(e.graphics)
End Sub

What this Sub does is fairly simple. It calculates the degrees the hands need to be at, then calls the draw Sub for the corresponding object.

Why not run your program now and watch the hands move across the screen?

Step 5

Dressing it up

Here, you create a Sub named drawFace. You can add anything you want to it. I opted to fill in the ellipses with textures instead of gradients (look better that way).

VB.NET
Private Sub drawFace(ByVal g As Graphics)
    Dim path As String = Mid(Application.ExecutablePath, 1, _
                      InStrRev(Application.ExecutablePath, "\"))
    Dim grdFace As New TextureBrush(New Bitmap(path & "\face.jpg"))
    Dim grdWatch As New TextureBrush(New Bitmap(path & "\watch.jpg"))

    g.FillEllipse(grdWatch, New Rectangle(5, 5, 290, 290))
    g.FillEllipse(Brushes.Black, New Rectangle(15, 15, 270, 270))
    g.FillEllipse(grdFace, New Rectangle(20, 20, 260, 260))

    Dim f As New Font("Arial", 10, FontStyle.Bold)
    Dim Sze = g.MeasureString("Powered by Visual Basic.NET", f)
    g.DrawString("Powered by Visual Basic.NET", f, _
                 Brushes.Black, (300 - Sze.width) / 2, 200)

    grdFace.Dispose()
    grdWatch.Dispose()

    ' Don't dispose g !
End Sub

The last thing you need to do is add the drawFace command to your paint Sub like this:

VB.NET
Private Sub clock_Paint(ByVal sender As Object, _
     ByVal e As System.Windows.Forms.PaintEventArgs) Handles clock.Paint
   drawFace(e.Graphics)

   ...
   ...
   ...

End Sub

Well, that's it, you should now have a working clock with a cool looking face.

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


Written By
Web Developer
United States United States
I started programming for fun when I was about 10 on an Franklin Ace 1000.

I still do it just for fun but it has gotten me a few jobs over the years. More then I can say for my Microsoft Certifications. Smile | :)

The way I learned was by example, now its time to give back to the next generation of coders.



Comments and Discussions

 
GeneralMy vote of 2 Pin
Shane Story12-May-09 4:05
Shane Story12-May-09 4:05 
GeneralPretty coo' Pin
Thomas R. Wolfe31-May-07 12:40
Thomas R. Wolfe31-May-07 12:40 
GeneralRe: Pretty coo' Pin
Matthew Hazlett31-May-07 13:10
Matthew Hazlett31-May-07 13:10 
GeneralNice clock! Pin
Hamfiles27-May-07 15:59
Hamfiles27-May-07 15:59 
GeneralCompiles but ERR's Pin
smitsc24-Feb-06 7:08
smitsc24-Feb-06 7:08 
GeneralRe: Compiles but ERR's Pin
Pav99913-May-06 6:34
Pav99913-May-06 6:34 
GeneralIs possible make this clock Pin
akorolev1012-Oct-04 20:50
akorolev1012-Oct-04 20:50 
GeneralRe: Is possible make this clock Pin
Evert Meulie20-Jan-05 18:26
sussEvert Meulie20-Jan-05 18:26 
GeneralNot showing exact hour hand Pin
Karthikeyan Muthurajan12-Aug-04 23:31
Karthikeyan Muthurajan12-Aug-04 23:31 
GeneralRe: Not showing exact hour hand Pin
John Harald Apeland14-Aug-05 12:48
sussJohn Harald Apeland14-Aug-05 12:48 
GeneralRe: Not showing exact hour hand Pin
14-Aug-05 13:09
suss14-Aug-05 13:09 
GeneralAnalog watch Pin
Member 36670219-May-04 12:35
Member 36670219-May-04 12:35 
GeneralDoesnt Work Too Many Errors Pin
SimplySurfin31-Mar-04 10:17
SimplySurfin31-Mar-04 10:17 
GeneralRe: Doesnt Work Too Many Errors Pin
Matthew Hazlett31-Mar-04 10:43
Matthew Hazlett31-Mar-04 10:43 
QuestionPower by Visual Basic? Pin
NormDroid8-Jan-04 20:42
professionalNormDroid8-Jan-04 20:42 
GeneralBefore you ask :-) Pin
Matthew Hazlett8-Jan-04 15:04
Matthew Hazlett8-Jan-04 15:04 
GeneralRe: Before you ask :-) Pin
andremoraes14-Jan-04 8:35
andremoraes14-Jan-04 8:35 

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.