Home
Search
 
What's New
Index
Books
Links
Q & A
Newsletter
Banners
 
Feedback
Tip Jar
 
C# Helper...
 
XML RSS Feed
Follow VBHelper on Twitter
 
 
 
MSDN Visual Basic Community
 
 
 
 
 
TitleMake an analog clock with a shaped form in VB .NET
DescriptionThis example shows how to make an analog clock with a shaped form in VB .NET.
Keywordsanalog, clock, time, position, lower right, rotated text
CategoriesMultimedia, Graphics, Utilities, VB.NET
 
Subroutine DrawFace draws the clock's face. It makes a Bitmap to fit the form and fills it with purple. It then draws an ellipse for the clock face and outlines it.

Next the routine loops as i runs from 1 to 60 minutes. If i is a multiple of 5, it draws an hour number on the clock by calling subroutine DrawRotatedText. It then draws a tick mark for the minute.

When it finishes, the routine sets the form's BackgroundImage to the face bitmap and sets the form's TransparencyKey to Purple. That makes the purple parts of the form that lie outside of the clock face invisible.

 
' Draw the clock's face without hands.
Private Sub DrawFace()
    ' Make a Bitmap to hold the clock face.
    m_Face = New Bitmap(Me.ClientRectangle.Width, _
        Me.ClientRectangle.Height)
    Dim gr As Graphics = Graphics.FromImage(m_Face)

    ' Use a purple background. This will later be
    ' transparent.
    gr.Clear(Color.Purple)

    ' Fill the clock face with CornflowerBlue.
    Dim inner_rect As New Rectangle(0, 0, _
        Me.ClientRectangle.Width - 1, _
        Me.ClientRectangle.Height - 1)
    gr.FillEllipse(Brushes.CornflowerBlue, inner_rect)

    ' Draw the clock face.
    gr.DrawEllipse(Pens.Blue, inner_rect)

    ' Draw the tic marks and numerals.
    Dim cx As Integer = (Me.ClientRectangle.Width - 1) \ 2
    Dim cy As Integer = (Me.ClientRectangle.Height - 1) \ 2
    Dim dtheta As Double = PI / 30
    Dim theta As Double = -10 * dtheta
    Dim x1, y1, x2, y2 As Double
    Dim txt As String
    For i As Integer = 0 To 59
        ' Draw the tic marks.
        x1 = cx + cx * Cos(theta)
        y1 = cy + cy * Sin(theta)
        If i Mod 5 = 0 Then
            ' Label the digit.
            txt = (i \ 5 + 1).ToString()

            ' Find the point lined up along the tic mark.
            x2 = cx + (cx - 1) * Cos(theta) * 0.8
            y2 = cy + (cy - 1) * Sin(theta) * 0.8

            ' Create a rotated font.
            DrawRotatedText(gr, txt, _
                CSng(360 * (i + 5) / 60), _
                x2, y2)

            x2 = cx + cx * Cos(theta) * 0.9
            y2 = cy + cy * Sin(theta) * 0.9
        Else
            x2 = cx + cx * Cos(theta) * 0.95
            y2 = cy + cy * Sin(theta) * 0.95
        End If
        gr.DrawLine(Pens.Blue, CSng(x1), CSng(y1), _
            CSng(x2), CSng(y2))
        theta += dtheta
    Next i

    ' Display the clock face on the form's background.
    Me.BackgroundImage = m_Face

    ' Set TransparencyKey so the purple background is
    ' transparent.
    Me.TransparencyKey = Color.Purple
End Sub
 
Subroutine DrawRotatedText makes a StringFormat object that centers text. It makes a GraphicsPath object that draws the necessary text at the desired location, applies a transformation that rotates the text around the point, and then fills and draws the path.
 
' Draw text centered at (cx, cy) and 
' rotated by angle degrees.
Private Sub DrawRotatedText(ByVal gr As Graphics, ByVal txt _
    As String, ByVal angle As Single, ByVal cx As Double, _
    ByVal cy As Double)
    ' Make a StringFormat that centers text.
    Dim string_format As New StringFormat
    string_format.Alignment = StringAlignment.Center
    string_format.LineAlignment = StringAlignment.Center

    ' Make a GraphicsPath that draws the text.
    Dim graphics_path As New GraphicsPath( _
        Drawing.Drawing2D.FillMode.Winding)
    Dim ix As Integer = CInt(cx)
    Dim iy As Integer = CInt(cy)
    graphics_path.AddString(txt, _
        Me.Font.FontFamily, _
        Me.Font.Style, Me.Font.Size, _
        New Point(ix, iy), _
        string_format)

    ' Make a rotation matrix representing 
    ' rotation around the point (ix, iy).
    Dim rotation_matrix As New Matrix
    rotation_matrix.RotateAt(angle, New PointF(ix, iy))

    ' Transform the GraphicsPath.
    graphics_path.Transform(rotation_matrix)

    ' Draw the text.
    gr.FillPath(Brushes.Black, graphics_path)
    gr.DrawPath(Pens.Black, graphics_path)
End Sub
 
The form's Paint event handler draws the clock's face and hands. It starts by drawing the saved clock face onto the event handler's e.Graphics object. It then draws the hour, minute, and second hands.
 
' Draw the clock's face with hands.
Private Sub Form1_Paint(ByVal sender As Object, ByVal e As _
    System.Windows.Forms.PaintEventArgs) Handles _
    MyBase.Paint
    Const HOUR_R As Double = 0.3
    Const MIN_R As Double = 0.5
    Const SEC_R As Double = 0.75

    If m_Face Is Nothing Then Exit Sub

    ' Copy the face onto the bitmap.
    e.Graphics.DrawImage(m_Face, 0, 0)

    ' Draw the hands.
    Dim cx As Double = Me.ClientRectangle.Width / 2
    Dim cy As Double = Me.ClientRectangle.Height / 2
    Dim x1, y1, theta As Double

    ' Draw the hour hand.
    Dim time_span As TimeSpan = Now.TimeOfDay()
    theta = time_span.TotalHours() / 12 * 2 * PI - PI / 2
    x1 = cx + cx * Cos(theta) * HOUR_R
    y1 = cy + cy * Sin(theta) * HOUR_R
    e.Graphics.DrawLine(Pens.Red, _
        CSng(cx), CSng(cy), CSng(x1), CSng(y1))

    ' Draw the minute hand.
    theta = time_span.TotalMinutes() / 60 * 2 * PI - PI / 2
    x1 = cx + cx * Cos(theta) * MIN_R
    y1 = cy + cy * Sin(theta) * MIN_R
    e.Graphics.DrawLine(Pens.Blue, _
        CSng(cx), CSng(cy), CSng(x1), CSng(y1))

    ' Draw the second hand.
    theta = time_span.TotalSeconds() / 60 * 2 * PI - PI / 2
    x1 = cx + cx * Cos(theta) * MIN_R
    y1 = cy + cy * Sin(theta) * MIN_R
    e.Graphics.DrawLine(Pens.White, _
        CSng(cx), CSng(cy), CSng(x1), CSng(y1))

    ' Draw a circle in the middle.
    e.Graphics.FillEllipse(Brushes.Black, _
        CSng(cx - 3), CSng(cy - 3), 5, 5)
End Sub
 
Every second, the program's tmrTick Timer fires. The event handler invalidates the form's surface to cause a Paint event.
 
' Invalidate to cause a Paint.
Private Sub tmrTick_Tick(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles tmrTick.Tick
    Me.Invalidate()
End Sub
 
 
Copyright © 1997-2010 Rocky Mountain Computer Consulting, Inc.   All rights reserved.
  Updated