Click here to Skip to main content
15,885,546 members
Articles / Multimedia / GDI+

Analog Clock Control

Rate me:
Please Sign up or sign in to vote.
4.58/5 (66 votes)
23 Jan 2010CPOL4 min read 319K   30.7K   138  
The analog clock control is a control that has almost all the functionality that a clock control can have, and it is fully modifiable.
'Author: Arman Ghazanchyan
'Created date: 06/18/2007

<Assembly: CLSCompliant(True)> 

#Region " Enumeration "

''' <summary>
''' Represents border-style enumeration for AnalogClock.Clock control.
''' </summary>
<Flags()> _
Public Enum BorderStyles As Integer
    None = 0
    Round = 1
    FixedSingle = 2
    RoundFrame = 4
    RoundFixedSingle = (Round Or RoundFrame)
    FixedSingleRoundFrame = (FixedSingle Or RoundFrame)
End Enum

#End Region

''' <summary>
''' Represents a AnalogClock.Clock control for windows.
''' </summary>
<DebuggerNonUserCode()> _
<System.ComponentModel.DefaultProperty("Name"), _
System.ComponentModel.DefaultEvent("TimeChanged"), _
DebuggerDisplay("DateTime = {DateTime}"), _
System.ComponentModel.Description("Displays analog clock."), _
ToolboxBitmap(GetType(Clock), "clock.bmp"), _
System.ComponentModel.DefaultBindingProperty("UtcOffset")> _
Public Class Clock

#Region " Event Handlers "

    <System.ComponentModel.Category("Property Changed"), System.ComponentModel.Description("Occurs when the clock's time changed.")> _
    Public Event TimeChanged As System.EventHandler
    <System.ComponentModel.Category("Property Changed"), System.ComponentModel.Description("Occurs when the clock's UTC changed.")> _
    Public Event UtcChanged As System.EventHandler
    <System.ComponentModel.Category("Property Changed"), System.ComponentModel.Description("Occurs when the clock's update changed.")> _
    Public Event ClockRunningChanged As System.EventHandler
    <System.ComponentModel.Category("Elements"), System.ComponentModel.Description("Occurs when an element property changed.")> _
    Public Event ElementPropertyChanged As System.ComponentModel.PropertyChangedEventHandler
    <System.ComponentModel.Category("Property Changed"), System.ComponentModel.Description("Occurs when the clock's frame color changed.")> _
    Public Event FrameColorChanged As EventHandler
    <System.ComponentModel.Category("Property Changed"), System.ComponentModel.Description("Occurs when the clock's border style changed.")> _
    Public Event BorderStyleChanged As EventHandler
    <System.ComponentModel.Category("Property Changed"), System.ComponentModel.Description("Occurs when the clock's update frequency changed.")> _
    Public Event UpdateFrequencyChanged As EventHandler
    <System.ComponentModel.Category("Appearance"), System.ComponentModel.Description("Occurs when the clock's background needs repainting.")> _
    Public Event BackgroundPaint As System.Windows.Forms.PaintEventHandler
    <System.ComponentModel.Category("Elements"), System.ComponentModel.Description("Occurs when a small-marker object needs repainting.")> _
    Public Event SmallMarkerPainting As EventHandler(Of AnalogClock.PaintEventArgs)
    <System.ComponentModel.Category("Elements"), System.ComponentModel.Description("Occurs when a small-marker objects had been painted.")> _
    Public Event SmallMarkerPainted As System.Windows.Forms.PaintEventHandler
    <System.ComponentModel.Category("Elements"), System.ComponentModel.Description("Occurs when all small-marker objects had been painted.")> _
    Public Event SmallMarkersPainted As System.Windows.Forms.PaintEventHandler
    <System.ComponentModel.Category("Elements"), System.ComponentModel.Description("Occurs when a big-marker object needs repainting.")> _
    Public Event BigMarkerPainting As EventHandler(Of AnalogClock.PaintEventArgs)
    <System.ComponentModel.Category("Elements"), System.ComponentModel.Description("Occurs when a big-marker objects had been painted.")> _
    Public Event BigMarkerPainted As System.Windows.Forms.PaintEventHandler
    <System.ComponentModel.Category("Elements"), System.ComponentModel.Description("Occurs when all big-marker objects had been painted.")> _
    Public Event BigMarkersPainted As System.Windows.Forms.PaintEventHandler
    <System.ComponentModel.Category("Appearance"), System.ComponentModel.Description("Occurs when the clock's frame needs repainting.")> _
    Public Event FramePainting As System.Windows.Forms.PaintEventHandler
    <System.ComponentModel.Category("Appearance"), System.ComponentModel.Description("Occurs when the clock's frame had been painted.")> _
    Public Event FramePainted As System.Windows.Forms.PaintEventHandler
    <System.ComponentModel.Category("Elements"), System.ComponentModel.Description("Occurs when a symbol object needs repainting.")> _
    Public Event SymbolPainting As EventHandler(Of AnalogClock.PaintEventArgs)
    <System.ComponentModel.Category("Elements"), System.ComponentModel.Description("Occurs when a symbol objects had been painted.")> _
    Public Event SymbolPainted As System.Windows.Forms.PaintEventHandler
    <System.ComponentModel.Category("Elements"), System.ComponentModel.Description("Occurs when all symbol objects had been painted.")> _
    Public Event SymbolsPainted As System.Windows.Forms.PaintEventHandler
    <System.ComponentModel.Category("Elements"), System.ComponentModel.Description("Occurs when a custom symbol painting is required.")> _
    Public Event CustomSymbolPainting As PaintEventHandler
    <System.ComponentModel.Category("Elements"), System.ComponentModel.Description("Occurs when the hour-hand object needs repainting.")> _
    Public Event HourHandPainting As EventHandler(Of AnalogClock.PaintEventArgs)
    <System.ComponentModel.Category("Elements"), System.ComponentModel.Description("Occurs when the hour-hand object had been painted.")> _
    Public Event HourHandPainted As System.Windows.Forms.PaintEventHandler
    <System.ComponentModel.Category("Elements"), System.ComponentModel.Description("Occurs when the minute-hand object needs repainting.")> _
    Public Event MinuteHandPainting As EventHandler(Of AnalogClock.PaintEventArgs)
    <System.ComponentModel.Category("Elements"), System.ComponentModel.Description("Occurs when the minute-hand object had been painted.")> _
    Public Event MinuteHandPainted As System.Windows.Forms.PaintEventHandler
    <System.ComponentModel.Category("Elements"), System.ComponentModel.Description("Occurs when the second-hand object needs repainting.")> _
    Public Event SecondHandPainting As EventHandler(Of AnalogClock.PaintEventArgs)
    <System.ComponentModel.Category("Elements"), System.ComponentModel.Description("Occurs when the second-hand object had been painted.")> _
    Public Event SecondHandPainted As System.Windows.Forms.PaintEventHandler
    <System.ComponentModel.Category("Elements"), System.ComponentModel.Description("Occurs when the center-point object needs repainting.")> _
    Public Event CenterPointPainting As EventHandler(Of AnalogClock.PaintEventArgs)
    <System.ComponentModel.Category("Elements"), System.ComponentModel.Description("Occurs when the center-point object had been painted.")> _
    Public Event CenterPointPainted As System.Windows.Forms.PaintEventHandler
    <System.ComponentModel.Category("Elements"), System.ComponentModel.Description("Occurs when a custom element's GraphicsPath object is required.")> _
    Public Event CustomElementRequest As EventHandler(Of AnalogClock.CustomElementEventArgs)

#End Region

#Region " Members "

    Private _borderStyle As AnalogClock.BorderStyles
    Private _rect As RectangleF
    Private _dateTime As DateTime
    Private _frameColor As Color = Color.Black
    Private _radius As Single
    Private _utcOffset As TimeSpan
    Private WithEvents _hourHand As Hand
    Private WithEvents _minuteHand As Hand
    Private WithEvents _secondHand As Hand
    Private WithEvents _centerPoint As Center
    Private _bigMarkers(11) As Marker
    Private _smallMarkers(59) As Marker
    Private _symbols(11) As Symbol
    Private _symbolsInitalized As Boolean
    Private _bigMarkersInitalized As Boolean
    Private _smallMarkersInitalized As Boolean

#End Region

#Region " Properties "

    ''' <summary>
    ''' Gets clock's hour-hand object.
    ''' </summary>
    <System.ComponentModel.Category("Elements"), System.ComponentModel.Description("Represents clock's hour-hand object."), _
    System.ComponentModel.DesignerSerializationVisibilityAttribute(System.ComponentModel.DesignerSerializationVisibility.Content)> _
    Public ReadOnly Property HourHand() As Hand
        Get
            Return Me._hourHand
        End Get
    End Property

    ''' <summary>
    ''' Gets clock's minute-hand object.
    ''' </summary>
    <System.ComponentModel.Category("Elements"), System.ComponentModel.Description("Represents clock's minute-hand object."), _
    System.ComponentModel.DesignerSerializationVisibilityAttribute(System.ComponentModel.DesignerSerializationVisibility.Content)> _
    Public ReadOnly Property MinuteHand() As Hand
        Get
            Return Me._minuteHand
        End Get
    End Property

    ''' <summary>
    ''' Gets clock's second-hand object.
    ''' </summary>
    <System.ComponentModel.Category("Elements"), System.ComponentModel.Description("Represents clock's second-hand object."), _
    System.ComponentModel.DesignerSerializationVisibilityAttribute(System.ComponentModel.DesignerSerializationVisibility.Content)> _
    Public ReadOnly Property SecondHand() As Hand
        Get
            Return Me._secondHand
        End Get
    End Property

    ''' <summary>
    ''' Gets clock's center-point object.
    ''' </summary>
    <System.ComponentModel.Category("Elements"), System.ComponentModel.Description("Represents clock's center-point object."), _
    System.ComponentModel.DesignerSerializationVisibilityAttribute(System.ComponentModel.DesignerSerializationVisibility.Content)> _
    Public ReadOnly Property CenterPoint() As Center
        Get
            Return Me._centerPoint
        End Get
    End Property

    ''' <summary>
    ''' Gets or sets the clock's big-marker array.
    ''' </summary>
    <System.ComponentModel.Category("Elements"), System.ComponentModel.Description("Represents an array of clock's big-markers."), _
    System.ComponentModel.Editor(GetType(ElementArrayEditor), GetType(Drawing.Design.UITypeEditor)), _
    System.ComponentModel.DesignerSerializationVisibilityAttribute(System.ComponentModel.DesignerSerializationVisibility.Content), _
    System.ComponentModel.TypeConverterAttribute(GetType(ElementArrayConverter))> _
    Public Property BigMarkers() As Marker()
        Get
            Return Me._bigMarkers
        End Get
        Set(ByVal bigMarkers As Marker())
            If bigMarkers Is Nothing Then
                Throw New ArgumentNullException("bigMarkers")
            Else
                If bigMarkers.Length <> 12 Then
                    Throw New ArgumentOutOfRangeException( _
                    "bigMarkers", bigMarkers, "The clock must have 12 big-markers!")
                Else
                    If Not Me._bigMarkersInitalized OrElse (Me._bigMarkers(0) IsNot bigMarkers(0)) Then
                        Me.InitalizeBigMarkers(bigMarkers)
                        Me._bigMarkersInitalized = True
                    End If
                    Me._bigMarkers = bigMarkers
                    Me.Invalidate(False)
                End If
            End If
        End Set
    End Property

    ''' <summary>
    ''' Gets or sets the clock's small-marker array.
    ''' </summary>
    <System.ComponentModel.Category("Elements"), System.ComponentModel.Description("Represents an array of clock's small-markers."), _
    System.ComponentModel.Editor(GetType(ElementArrayEditor), GetType(Drawing.Design.UITypeEditor)), _
    System.ComponentModel.DesignerSerializationVisibilityAttribute(System.ComponentModel.DesignerSerializationVisibility.Content), _
    System.ComponentModel.TypeConverterAttribute(GetType(ElementArrayConverter))> _
    Public Property SmallMarkers() As Marker()
        Get
            Return Me._smallMarkers
        End Get
        Set(ByVal smallMarkers As Marker())
            If smallMarkers Is Nothing Then
                Throw New ArgumentNullException("smallMarkers")
            Else
                If smallMarkers.Length <> 60 Then
                    Throw New ArgumentOutOfRangeException( _
                    "smallMarkers", smallMarkers, "The clock must have 60 small-markers!")
                Else
                    If Not Me._smallMarkersInitalized OrElse Me._smallMarkers(0) IsNot smallMarkers(0) Then
                        Me.InitalizeSmallMarkers(smallMarkers)
                        Me._smallMarkersInitalized = True
                    End If
                    Me._smallMarkers = smallMarkers
                    Me.Invalidate(False)
                End If
            End If
        End Set
    End Property

    ''' <summary>
    ''' Gets or sets the clock's symbol array.
    ''' </summary>
    <System.ComponentModel.Category("Elements"), System.ComponentModel.Description("Represents an array of clock's symbols."), _
    System.ComponentModel.Editor(GetType(ElementArrayEditor), GetType(Drawing.Design.UITypeEditor)), _
    System.ComponentModel.DesignerSerializationVisibilityAttribute(System.ComponentModel.DesignerSerializationVisibility.Content), _
    System.ComponentModel.TypeConverterAttribute(GetType(ElementArrayConverter))> _
    Public Property Symbols() As Symbol()
        Get
            Return Me._symbols
        End Get
        Set(ByVal symbols As Symbol())
            If symbols Is Nothing Then
                Throw New ArgumentNullException("symbols")
            Else
                If symbols.Length <> 12 Then
                    Throw New ArgumentOutOfRangeException( _
                    "symbols", symbols, "The clock must have 12 symbols!")
                Else
                    If Not Me._symbolsInitalized OrElse Me._symbols(0) IsNot symbols(0) Then
                        Me.InitalizeSymbols(symbols)
                        Me._symbolsInitalized = True
                    End If
                    Me._symbols = symbols
                    Me.Invalidate(False)
                End If
            End If
        End Set
    End Property

    ''' <summary>
    ''' Gets or sets the clock's Coordinated Universal Time (UTC) offset.
    ''' </summary>
    <System.ComponentModel.DefaultValue(GetType(TimeSpan), "00:00:00"), _
    System.ComponentModel.Bindable(True), System.ComponentModel.Category("Behavior"), _
    System.ComponentModel.RefreshPropertiesAttribute(System.ComponentModel.RefreshProperties.Repaint), _
    System.ComponentModel.Description( _
    "Indicates the clock's Coordinated Universal Time (UTC) offset.")> _
    Public Property UtcOffset() As TimeSpan
        Get
            Return Me._utcOffset
        End Get
        Set(ByVal utcOffset As TimeSpan)
            If utcOffset < TimeSpan.Parse("-23:59:00") OrElse utcOffset > TimeSpan.Parse("23:59:00") Then
                Throw New ArgumentOutOfRangeException( _
                "utcOffset", utcOffset, "The value must be in the range -23:59:00 to 23:59:00.")
            Else
                If Me._utcOffset <> utcOffset Then
                    Me._utcOffset = utcOffset
                    Me.UpdateTime()
                    Me.OnUtcChanged(New System.EventArgs)
                End If
            End If
        End Set
    End Property

    ''' <summary>
    ''' Gets or sets the clock's frame color.
    ''' </summary>
    <System.ComponentModel.DefaultValue(GetType(Color), "Black"), _
    System.ComponentModel.Bindable(True), System.ComponentModel.Category("Appearance"), _
    System.ComponentModel.Description("Indicates the clock's frame color.")> _
    Public Property FrameColor() As Color
        Get
            Return Me._frameColor
        End Get
        Set(ByVal value As Drawing.Color)
            If Me._frameColor <> value Then
                Me._frameColor = value
                Me.Invalidate(False)
                Me.OnFrameColorChanged(New System.EventArgs)
            End If
        End Set
    End Property

    ''' <summary>
    ''' Gets or sets a value indicating whether the clock is running.
    ''' </summary>
    <System.ComponentModel.DefaultValue(True), _
    System.ComponentModel.Bindable(True), System.ComponentModel.Category("Behavior"), _
    System.ComponentModel.Description("Indicates whether the clock is running.")> _
    Public Property Running() As Boolean
        Get
            Return Me.UpdateTimer.Enabled
        End Get
        Set(ByVal value As Boolean)
            If Me.UpdateTimer.Enabled <> value Then
                Me.UpdateTimer.Enabled = value
                Me.UpdateTime()
                Me.OnClockRunningChanged(New System.EventArgs)
            End If
        End Set
    End Property

    ''' <summary>
    ''' Gets or sets the clock's border style.
    ''' </summary>
    <System.ComponentModel.DefaultValue(GetType(BorderStyles), "None"), _
    System.ComponentModel.Bindable(True), System.ComponentModel.Category("Appearance"), _
    System.ComponentModel.Description("Indicates the clock's border style")> _
    Public Overloads Property BorderStyle() As AnalogClock.BorderStyles
        Get
            Return Me._borderStyle
        End Get
        Set(ByVal borderStyle As AnalogClock.BorderStyles)
            If Not [Enum].IsDefined(GetType(BorderStyles), borderStyle) Then
                Throw New System.ComponentModel.InvalidEnumArgumentException("borderStyle", borderStyle, GetType(BorderStyles))
            Else
                If Me._borderStyle <> borderStyle Then
                    Me._borderStyle = borderStyle
                    Me.SetClockRegion()
                    Me.Refresh()
                    Me.OnBorderStyleChanged(New System.EventArgs)
                End If
            End If
        End Set
    End Property

    ''' <summary>
    ''' Gets or sets the clock's update frequency (in milliseconds).
    ''' </summary>
    <System.ComponentModel.DefaultValue(100), _
    System.ComponentModel.Bindable(True), System.ComponentModel.Category("Behavior"), _
    System.ComponentModel.Description("Indicates the clock's update frequency (in milliseconds).")> _
    Public Property UpdateFrequency() As Integer
        Get
            Return Me.UpdateTimer.Interval
        End Get
        Set(ByVal updateFrequency As Integer)
            If (updateFrequency > 100 OrElse updateFrequency < 1) AndAlso Math.IEEERemainder(100, updateFrequency) <> 0 Then
                Dim sb As New System.Text.StringBuilder
                sb.AppendLine("The value should be in the range 1 to 100 and must divide 100 without a remainder.")
                sb.AppendLine("Example:")
                sb.AppendLine("1")
                sb.AppendLine("2")
                sb.AppendLine("4")
                sb.AppendLine("5")
                sb.AppendLine("10")
                sb.AppendLine("20")
                sb.AppendLine("25")
                sb.AppendLine("50")
                sb.AppendLine("100")
                Throw New ArgumentOutOfRangeException("updateFrequency", updateFrequency, sb.ToString)
            Else
                Me.UpdateTimer.Interval = updateFrequency
                Me.OnUpdateFrequencyChanged(New EventArgs)
            End If
        End Set
    End Property

    ''' <summary>
    ''' Gets the clock's date and time object.
    ''' </summary>
    <System.ComponentModel.Category("Behavior"), System.ComponentModel.Description("The clock's date and time.")> _
    Public ReadOnly Property Value() As System.DateTime
        Get
            Return Me._dateTime
        End Get
    End Property

    ''' <summary>
    ''' Gets clock's drawing rectangle.
    ''' </summary>
    <System.ComponentModel.Browsable(False)> _
    Public ReadOnly Property Rectangle() As RectangleF
        Get
            Return Me._rect
        End Get
    End Property

    ''' <summary>
    ''' Gets clock's radius.
    ''' </summary>
    <System.ComponentModel.Browsable(False)> _
    Public ReadOnly Property Radius() As Single
        Get
            Return Me._radius
        End Get
    End Property

    ''' <summary>
    ''' Gets a value that indicates whether the clock has been initialized.
    ''' </summary>
    <System.ComponentModel.Browsable(False)> _
    Public ReadOnly Property Initialized() As Boolean
        Get
            Return (Me._bigMarkersInitalized And Me._smallMarkersInitalized And Me._symbolsInitalized)
        End Get
    End Property

#End Region

#Region " Methods "

    Sub New()

        ' This call is required by the Windows Form Designer.
        InitializeComponent()
        ' Add any initialization after the InitializeComponent() call.

        Me.SetClockRectangle()
        ' Create hour-hand object.
        Me._hourHand = New Hand("HourHand", Me._radius, 0.65F, 5.0F, 0.2F, 30)
        ' Create minute-hand object.
        Me._minuteHand = New Hand("MinuteHand", Me._radius, 0.8F, 5.0F, 0.2F, 6)
        ' Create second-hand object.
        Me._secondHand = New Hand("SecondHand", Me._radius, 0.9F, 1.0F, 0.2F, 6)
        ' Create center-point object.
        Me._centerPoint = New Center(Me._radius, 0.03F)
        ' Update the graphics paths of the elements.
        Me.HourHand.UpdateBasePath()
        Me.MinuteHand.UpdateBasePath()
        Me.SecondHand.UpdateBasePath()
        Me.CenterPoint.UpdateBasePath()
    End Sub

    ''' <summary>
    ''' Calculates and returns a point in the clock's cordinates.
    ''' </summary>
    ''' <param name="startPoint">A starting point in the clock’s 
    ''' area from which the point should be calculated.</param>
    ''' <param name="angle">An angle from x-axis (in radins).</param>
    ''' <param name="radius">The distans from the starting point to the point.</param>
    Public Shared Function GetPoint(ByVal startPoint As PointF, ByVal angle As Double, ByVal radius As Single) As PointF
        Dim y, x As Single
        y = CSng(startPoint.Y - (Math.Sin(angle) * radius))
        x = CSng(startPoint.X + (Math.Cos(angle) * radius))
        Return New PointF(x, y)
    End Function

    ''' <summary>
    ''' Updates the clock's hands.
    ''' </summary>
    Private Sub UpdateTime()
        Me._dateTime = Date.UtcNow.AddTicks(Me._utcOffset.Ticks)
        Static Dim sec As Integer = -1
        If Me._secondHand.Motion = HandMotion.Step Then
            Me._secondHand.Value = Me._dateTime.Second
        Else
            Me._secondHand.Value = Me._dateTime.Second + Me._dateTime.Millisecond / 1000
        End If
        If Me.MinuteHand.Motion = HandMotion.Step Then
            Me._minuteHand.Value = Me._dateTime.Minute
        Else
            Me._minuteHand.Value = Me._dateTime.Minute + Me._dateTime.Second / 60
        End If
        Me._hourHand.Value = Me._dateTime.Hour + Me._dateTime.Minute / 60
        If sec <> Me._dateTime.Second Then
            sec = Me._dateTime.Second
            Me.OnTimeChanged(New System.EventArgs)
        End If
    End Sub

    ''' <summary>
    ''' Sets the clock's rectangle and radius.
    ''' </summary>
    Private Sub SetClockRectangle()
        If Me.Width < Me.Height Then
            Me._rect = New RectangleF(0.0F, 0.0F, Me.Width, Me.Width)
        ElseIf Me.Width > Me.Height Then
            Me._rect = New RectangleF(0.0F, 0.0F, Me.Height, Me.Height)
        Else
            Me._rect = New RectangleF(0.0F, 0.0F, Me.Width, Me.Width)
        End If
        Me._radius = Me._rect.Width / 2.0F
    End Sub

    ''' <summary>
    ''' Sets the clock's region.
    ''' </summary>
    Private Sub SetClockRegion()
        If (Me._borderStyle And BorderStyles.Round) <> 0 Then
            Dim pa As New Drawing.Drawing2D.GraphicsPath
            pa.AddEllipse(Me._rect.X - 1.0F, Me._rect.Y - 1.0F, Me._rect.Width + 1.0F, Me._rect.Height + 1.0F)
            pa.CloseAllFigures()
            Me.Region = New Region(pa)
            pa.Dispose()
        Else
            Dim pa As New Drawing.Drawing2D.GraphicsPath
            pa.AddRectangle(Me._rect)
            pa.CloseAllFigures()
            Me.Region = New Region(pa)
            pa.Dispose()
        End If
    End Sub

    ''' <summary>
    ''' Initalizes the clock's big-markers by adding event handlers and updating the base-path.
    ''' </summary>
    ''' <param name="markerArray">An array of AnalogClock.Marker object.</param>
    Private Sub InitalizeBigMarkers(ByVal markerArray As Marker())
        For Each item As Marker In markerArray
            AddHandler item.PropertyChanged, AddressOf Me.Element_PropertyChanged
            AddHandler item.CustomElementRequest, AddressOf Me.Elements_CustomElementRequest
            AddHandler item.ElementPainting, AddressOf Me.BigMarkers_ElementPainting
            AddHandler item.ElementPainted, AddressOf Me.BigMarkers_ElementPainted
            item.UpdateBasePath()
        Next
    End Sub

    ''' <summary>
    ''' Initalizes the clock's small-markers by adding event handlers and updating the base-path.
    ''' </summary>
    ''' <param name="markerArray">An array of AnalogClock.Marker object.</param>
    Private Sub InitalizeSmallMarkers(ByVal markerArray As Marker())
        For Each item As Marker In markerArray
            AddHandler item.PropertyChanged, AddressOf Me.Element_PropertyChanged
            AddHandler item.CustomElementRequest, AddressOf Me.Elements_CustomElementRequest
            AddHandler item.ElementPainting, AddressOf Me.SmallMarkers_ElementPainting
            AddHandler item.ElementPainted, AddressOf Me.SmallMarkers_ElementPainted
            item.UpdateBasePath()
        Next
    End Sub

    ''' <summary>
    ''' Initalizes the clock's symbols by adding event handlers.
    ''' </summary>
    ''' <param name="symbolArray">An array of AnalogClock.Symbol object.</param>
    Private Sub InitalizeSymbols(ByVal symbolArray As Symbol())
        For Each item As Symbol In symbolArray
            AddHandler item.PropertyChanged, AddressOf Me.Element_PropertyChanged
            AddHandler item.CustomSymbolPainting, AddressOf Me.Symbols_ElementCustomPainting
            AddHandler item.ElementPainting, AddressOf Me.Symbols_ElementPainting
            AddHandler item.ElementPainted, AddressOf Me.Symbols_ElementPainted
        Next
    End Sub

#End Region

#Region " Events "

    Private Sub Clock_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        If Not Me._smallMarkersInitalized Then
            ' Create Small-Markers.
            For i As Integer = 0 To 59
                Dim angle As Integer = 90 - ((i) * 6)
                If angle < 0 Then
                    angle += 360
                End If
                Dim item As New Marker("SmallMarker" & angle, Me._radius, 1.0F, _
                                   angle, Color.Black, 1.0F, 0.03F, True)
                Me._smallMarkers(i) = item
                AddHandler item.PropertyChanged, AddressOf Me.Element_PropertyChanged
                AddHandler item.CustomElementRequest, AddressOf Me.Elements_CustomElementRequest
                AddHandler item.ElementPainting, AddressOf Me.SmallMarkers_ElementPainting
                AddHandler item.ElementPainted, AddressOf Me.SmallMarkers_ElementPainted
                item.UpdateBasePath()
            Next
            Me._smallMarkersInitalized = True
        End If
        If Not Me._bigMarkersInitalized Then
            ' Create Big-Markers.
            For i As Integer = 0 To 11
                Dim angle As Integer = 90 - ((i) * 30)
                If angle < 0 Then
                    angle += 360
                End If
                Dim item As New Marker("BigMarker" & angle, Me._radius, 1.0F, _
                                    angle, Color.Black, 1.0F, 0.06F)
                Me._bigMarkers(i) = item
                AddHandler item.PropertyChanged, AddressOf Me.Element_PropertyChanged
                AddHandler item.CustomElementRequest, AddressOf Me.Elements_CustomElementRequest
                AddHandler item.ElementPainting, AddressOf Me.BigMarkers_ElementPainting
                AddHandler item.ElementPainted, AddressOf Me.BigMarkers_ElementPainted
                item.UpdateBasePath()
            Next
            Me._bigMarkersInitalized = True
        End If
        If Not Me._symbolsInitalized Then
            ' Create Symbols.
            For i As Integer = 0 To 11
                Dim angle As Integer = 90 - ((i) * 30)
                If angle < 0 Then
                    angle += 360
                End If
                Dim item As New Symbol("Symbol" & angle, Me._radius, 0.82F, angle, i, New Point(1, 1))
                Me._symbols(i) = item
                AddHandler item.PropertyChanged, AddressOf Me.Element_PropertyChanged
                AddHandler item.CustomSymbolPainting, AddressOf Me.Symbols_ElementCustomPainting
                AddHandler item.ElementPainting, AddressOf Me.Symbols_ElementPainting
                AddHandler item.ElementPainted, AddressOf Me.Symbols_ElementPainted
            Next
            Me._symbolsInitalized = True
        End If

        ' Update the hands' values.
        Me.UpdateTime()
    End Sub

    Private Sub UpdateTimer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles UpdateTimer.Tick
        Me.UpdateTime()
    End Sub

    Private Sub Clock1_EnabledChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.EnabledChanged
        Me.Running = Me.Enabled
    End Sub

    Private Sub Elements_CustomElementRequest(ByVal sender As Object, ByVal e As CustomElementEventArgs) _
    Handles _centerPoint.CustomElementRequest, _hourHand.CustomElementRequest, _
    _minuteHand.CustomElementRequest, _secondHand.CustomElementRequest

        RaiseEvent CustomElementRequest(sender, e)
    End Sub

    Private Sub _hourHand_ElementPainted(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles _hourHand.ElementPainted
        RaiseEvent HourHandPainted(sender, e)
    End Sub

    Private Sub _hourHand_ElementPainting(ByVal sender As Object, ByVal e As PaintEventArgs) Handles _hourHand.ElementPainting
        RaiseEvent HourHandPainting(sender, e)
    End Sub

    Private Sub _minuteHand_ElementPainted(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles _minuteHand.ElementPainted
        RaiseEvent MinuteHandPainted(sender, e)
    End Sub

    Private Sub _minuteHand_ElementPainting(ByVal sender As Object, ByVal e As PaintEventArgs) Handles _minuteHand.ElementPainting
        RaiseEvent MinuteHandPainting(sender, e)
    End Sub

    Private Sub _secondHand_ElementPainted(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles _secondHand.ElementPainted
        RaiseEvent SecondHandPainted(sender, e)
    End Sub

    Private Sub _secondHand_ElementPainting(ByVal sender As Object, ByVal e As PaintEventArgs) Handles _secondHand.ElementPainting
        RaiseEvent SecondHandPainting(sender, e)
    End Sub

    Private Sub _centerPoint_ElementPainted(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles _centerPoint.ElementPainted
        RaiseEvent CenterPointPainted(sender, e)
    End Sub

    Private Sub _centerPoint_ElementPainting(ByVal sender As Object, ByVal e As PaintEventArgs) Handles _centerPoint.ElementPainting
        RaiseEvent CenterPointPainting(sender, e)
    End Sub

    Private Sub BigMarkers_ElementPainting(ByVal sender As Object, ByVal e As PaintEventArgs)
        RaiseEvent BigMarkerPainting(sender, e)
    End Sub

    Private Sub BigMarkers_ElementPainted(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs)
        RaiseEvent BigMarkerPainted(sender, e)
    End Sub

    Private Sub SmallMarkers_ElementPainting(ByVal sender As Object, ByVal e As PaintEventArgs)
        RaiseEvent SmallMarkerPainting(sender, e)
    End Sub

    Private Sub SmallMarkers_ElementPainted(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs)
        RaiseEvent SmallMarkerPainted(sender, e)
    End Sub

    Private Sub Symbols_ElementPainting(ByVal sender As Object, ByVal e As PaintEventArgs)
        RaiseEvent SymbolPainting(sender, e)
    End Sub

    Private Sub Symbols_ElementPainted(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs)
        RaiseEvent SymbolPainted(sender, e)
    End Sub

    Private Sub Symbols_ElementCustomPainting(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs)
        RaiseEvent CustomSymbolPainting(sender, e)
    End Sub

    Private Sub Element_PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Handles _
    _hourHand.PropertyChanged, _minuteHand.PropertyChanged, _secondHand.PropertyChanged, _centerPoint.PropertyChanged

        Me.Invalidate(False)
        RaiseEvent ElementPropertyChanged(sender, e)
    End Sub

#End Region

#Region " On Event "

    ''' <summary>
    ''' Raises the System.Windows.Forms.Control.Paint event.
    ''' </summary>
    Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)

        ' Paint clock's background.
        Me.OnBackgroundPaint(e)

        ' Paint all SmallMarkers
        For Each m As Marker In Me._smallMarkers
            m.Paint(e)
        Next
        Me.OnSmallMarkersPainted(e)

        ' Paint all BigMarkers
        For Each m As Marker In Me._bigMarkers
            m.Paint(e)
        Next
        Me.OnBigMarkersPainted(e)

        ' Paint all Symbols
        For Each s As Symbol In Me._symbols
            s.Paint(e)
        Next
        Me.OnSymbolsPainted(e)

        ' Paint the Hour-Hand
        Me._hourHand.Paint(e)

        ' Paint the Minute-Hand
        Me._minuteHand.Paint(e)

        ' Paint the Second-Hand
        Me._secondHand.Paint(e)

        'Paint the Center-Point
        Me._centerPoint.Paint(e)

        ' Paint the clock's frame.
        Me.OnFramePainting(e)

        ' Call the base paint event.
        MyBase.OnPaint(e)
    End Sub

    ''' <summary>
    ''' Raises the AnalogClock.Clock.BackgroundPaint event.
    ''' </summary>
    ''' <param name="e">A System.Windows.Forms.PaintEventArgs
    ''' that contains the event data.</param>
    Protected Overridable Sub OnBackgroundPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
        RaiseEvent BackgroundPaint(Me, e)
    End Sub

    ''' <summary>
    ''' Raises the AnalogClock.Clock.SmallMarkersPainted event.
    ''' </summary>
    ''' <param name="e">A System.Windows.Forms.PaintEventArgs
    ''' that contains the event data.</param>
    Protected Overridable Sub OnSmallMarkersPainted(ByVal e As System.Windows.Forms.PaintEventArgs)
        RaiseEvent SmallMarkersPainted(Me, e)
    End Sub

    ''' <summary>
    ''' Raises the AnalogClock.Clock.BigMarkersPainted event.
    ''' </summary>
    ''' <param name="e">A System.Windows.Forms.PaintEventArgs
    ''' that contains the event data.</param>
    Protected Overridable Sub OnBigMarkersPainted(ByVal e As System.Windows.Forms.PaintEventArgs)
        RaiseEvent BigMarkersPainted(Me, e)
    End Sub

    ''' <summary>
    ''' Raises the AnalogClock.Clock.SymbolssPainted event.
    ''' </summary>
    ''' <param name="e">A System.Windows.Forms.PaintEventArgs
    ''' that contains the event data.</param>
    Protected Overridable Sub OnSymbolsPainted(ByVal e As System.Windows.Forms.PaintEventArgs)
        RaiseEvent SymbolsPainted(Me, e)
    End Sub

    ''' <summary>
    ''' Raises the AnalogClock.Clock.FramePainting event.
    ''' </summary>
    ''' <param name="e">A System.Windows.Forms.PaintEventArgs
    ''' that contains the event data.</param>
    Protected Overridable Sub OnFramePainting(ByVal e As System.Windows.Forms.PaintEventArgs)
        RaiseEvent FramePainting(Me, e)
        Dim p As New Drawing.Pen(Me._frameColor)
        'Draw circle
        If (Me._borderStyle And BorderStyles.RoundFrame) <> 0 Then
            e.Graphics.DrawEllipse( _
            p, Me._rect.X, Me._rect.Y, Me._rect.Width - 1.0F, Me._rect.Height - 1.0F)
        End If
        'Draw Square
        If (Me._borderStyle And BorderStyles.FixedSingle) <> 0 Then
            e.Graphics.DrawRectangle( _
            p, Me._rect.X, Me._rect.Y, Me._rect.Width - 1.0F, Me._rect.Height - 1.0F)
        End If
        p.Dispose()
        Me.OnFramePainted(e)
    End Sub

    ''' <summary>
    ''' Raises the AnalogClock.Clock.FramePainted event.
    ''' </summary>
    ''' <param name="e">A System.Windows.Forms.PaintEventArgs
    ''' that contains the event data.</param>
    Protected Overridable Sub OnFramePainted(ByVal e As System.Windows.Forms.PaintEventArgs)
        RaiseEvent FramePainted(Me, e)
    End Sub

    ''' <summary>
    ''' Raises the System.Windows.Forms.Control.Resize event.
    ''' </summary>
    ''' <param name="e">A System.EventArgs
    ''' that contains the event data.</param>
    Protected Overrides Sub OnResize(ByVal e As System.EventArgs)
        Me.SetClockRectangle()
        Me.SetClockRegion()
        Me._centerPoint.ClockRadius = Me._radius
        Me._hourHand.ClockRadius = Me._radius
        Me._minuteHand.ClockRadius = Me._radius
        Me._secondHand.ClockRadius = Me._radius
        If Me._bigMarkersInitalized Then
            For Each item As Marker In Me._bigMarkers
                item.ClockRadius = Me._radius
            Next
        End If
        If Me._symbolsInitalized Then
            For Each item As Marker In Me._smallMarkers
                item.ClockRadius = Me._radius
            Next
        End If
        If Me._symbolsInitalized Then
            For Each item As Symbol In Me._symbols
                item.ClockRadius = Me._radius
            Next
        End If
    End Sub

    ''' <summary>
    ''' Raises the AnalogClock.Clock.TimeChanged event.
    ''' </summary>
    ''' <param name="e">A System.EventArgs
    ''' that contains the event data.</param>
    Protected Overridable Sub OnTimeChanged(ByVal e As System.EventArgs)
        RaiseEvent TimeChanged(Me, e)
    End Sub

    ''' <summary>
    ''' Raises the AnalogClock.Clock.UtcChanged event.
    ''' </summary>
    ''' <param name="e">A System.EventArgs
    ''' that contains the event data.</param>
    Protected Overridable Sub OnUtcChanged(ByVal e As System.EventArgs)
        RaiseEvent UtcChanged(Me, e)
    End Sub

    ''' <summary>
    ''' Raises the AnalogClock.Clock.FrameColorChanged event.
    ''' </summary>
    ''' <param name="e">A System.EventArgs
    ''' that contains the event data.</param>
    Protected Overridable Sub OnFrameColorChanged(ByVal e As System.EventArgs)
        RaiseEvent FrameColorChanged(Me, e)
    End Sub

    ''' <summary>
    ''' Raises the AnalogClock.Clock.BorderStyleChanged event.
    ''' </summary>
    ''' <param name="e">A System.EventArgs
    ''' that contains the event data.</param>
    Protected Overridable Sub OnBorderStyleChanged(ByVal e As System.EventArgs)
        RaiseEvent BorderStyleChanged(Me, e)
    End Sub

    ''' <summary>
    ''' Raises the AnalogClock.Clock.UpdateFrequencyChanged event.
    ''' </summary>
    ''' <param name="e">A System.EventArgs
    ''' that contains the event data.</param>
    Protected Overridable Sub OnUpdateFrequencyChanged(ByVal e As System.EventArgs)
        RaiseEvent UpdateFrequencyChanged(Me, e)
    End Sub

    ''' <summary>
    ''' Raises the AnalogClock.Clock.ClockRunningChanged event.
    ''' </summary>
    ''' <param name="e">A System.EventArgs
    ''' that contains the event data.</param>
    Protected Overridable Sub OnClockRunningChanged(ByVal e As System.EventArgs)
        RaiseEvent ClockRunningChanged(Me, e)
    End Sub

#End Region

End Class

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) ZipEdTech
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions