|
|
Title | Make an analog clock with a shaped form in VB .NET |
Description | This example shows how to make an analog clock with a shaped form in VB .NET. |
Keywords | analog, clock, time, position, lower right, rotated text |
Categories | Multimedia, 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
|
|
|
|
|
|