'Часы обыкновенные (c)2004 Denis Egorov.
'e-mail: (общий) bmp71@yandex.ru
'e-mail: (рабочий) denis@protis.ru
'Нарисованы с применением GDI+,
'методом соотношения 360 градусов к временным интервалам, 
'на примере окружности.
'Данная программа и ее код поставляется как есть.
'Вы можете использовать и модифицировать ее как Вам угодно.

Imports System.Drawing

Public Class Form1
    Inherits System.Windows.Forms.Form


#Region " Windows Form Designer generated code "

    Public Sub New()
        MyBase.New()

        'This call is required by the Windows Form Designer.
        InitializeComponent()

        'Add any initialization after the InitializeComponent() call

    End Sub

    'Form overrides dispose to clean up the component list.
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub

    'Required by the Windows Form Designer
    Private components As System.ComponentModel.IContainer

    'NOTE: The following procedure is required by the Windows Form Designer
    'It can be modified using the Windows Form Designer.  
    'Do not modify it using the code editor.
    Friend WithEvents Timer1 As System.Windows.Forms.Timer
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        Me.components = New System.ComponentModel.Container()
        Me.Timer1 = New System.Windows.Forms.Timer(Me.components)
        '
        'Timer1
        '
        Me.Timer1.Enabled = True
        Me.Timer1.Interval = 1000
        '
        'Form1
        '
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        Me.ClientSize = New System.Drawing.Size(300, 300)
        Me.Name = "Form1"

    End Sub

#End Region

    Protected Overrides Sub OnPaintBackground(ByVal pevent As System.Windows.Forms.PaintEventArgs)
        'OnPaintBackground делает перерисовку быстрее чем событие OnPaint
        'если очень много рисуем, битмапы двигаем, лучше это делать тут.
        Dim g As Graphics = pevent.Graphics()
        Dim h As Integer = Me.ClientSize.Height
        Dim w As Integer = Me.ClientSize.Width
        If h > w Then
            h = w
        Else
            w = h
        End If
        Dim pen1 As New Pen(Color.Black, 5)
        Dim brush1 As Brush = New SolidBrush(Color.Black)
        Dim point1 As New Point(0, 0)
        Dim size1 As New Size(w, h)
        Dim rect1 As New Rectangle(point1, size1)
        'заливка формы белым цветом
        g.Clear(Color.White)
        'перенос начала координат в центр
        'можно поделить на 2, можно умножить на 0.5  ....
        g.TranslateTransform(Me.ClientSize.Width * 0.5, Me.ClientSize.Height * 0.5)
        'далее будет применяться целочисленное деление
        'внешний круг
        g.DrawEllipse(pen1, -h \ 2, -h \ 2, h, h)
        'точка в центре
        g.FillEllipse(brush1, -h \ 20 \ 2, -h \ 20 \ 2, h \ 20, h \ 20)
        'штрихи часо-минут :-)
        Dim i As Integer
        For i = 1 To 12
            g.DrawLine(pen1, (h \ 2) - (h \ 10), 0, w \ 2, 0)
            g.RotateTransform(30)
        Next
    End Sub

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'Некоторые рекомендуемые параметры для рисования вручную
        '
        'говорим что рисуем сами
        SetStyle(ControlStyles.UserPaint, True)        '
        SetStyle(ControlStyles.AllPaintingInWmPaint, True)
        'Двойная буферизация, убирает мерцание при перерисовке
        SetStyle(ControlStyles.DoubleBuffer, True)

    End Sub

    Private Sub Form1_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Resize
        'принудительная перерисовка при изменении размера
        Me.Invalidate()
    End Sub

    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        'принудительная перерисовка, через 1 секунду
        Me.Invalidate()
    End Sub

    Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
        'здесь ходят стрелки часов
        'можно было-бы все это написать и в процедуре OnPaintBackground
        'все размеры завязаны на коэффицент J

        Dim g As Graphics = e.Graphics
        Dim brush1 As Brush = New SolidBrush(Color.Black)
        Dim brush2 As Brush = New SolidBrush(Color.Green)
        Dim font1 As Font = New Font("Arial", 30, FontStyle.Bold)

        Dim t As New DateTime()
        t = DateTime.Now

        Dim wh As New Size(Me.ClientSize.Width * 0.5, Me.ClientSize.Height * 0.5)
        Dim j As Integer = Me.ClientSize.Height
        If j > Me.ClientSize.Width Then j = Me.ClientSize.Width
        j *= 0.15 'Коэфицент размера стрелок

        'cекундная стрелка
        Dim ps1 As New Point(0, 0)
        Dim ps2 As New Point(j, -5)
        Dim ps3 As New Point(j * 2.5, 0)
        Dim ps4 As New Point(j, 5)
        Dim psts As Point() = {ps1, ps2, ps3, ps4}
        'минутная стрелка
        Dim pm1 As New Point(0, 0)
        Dim pm2 As New Point(j, -j * 0.1)
        Dim pm3 As New Point(j * 2, 0)
        Dim pm4 As New Point(j, j * 0.1)
        Dim pmts As Point() = {pm1, pm2, pm3, pm4}
        'часовая стрелка
        Dim ph1 As New Point(0, 0)
        Dim ph2 As New Point(j, -j * 0.17)
        Dim ph3 As New Point(j * 1.5, 0)
        Dim ph4 As New Point(j, j * 0.17)
        Dim phts As Point() = {ph1, ph2, ph3, ph4}

        'соотношение градусов к минутам
        '360 на 60 секунд, 6 градусов в секунду
        '360 на 60 минут,  6 градусов в минуту
        '360 на 12 часов,  30 градусов в час
        'P.S. в начале я поделил на 24, но на циферблате-то только 12 цифр :-)
        'используется вычет 90 градусов, так как по умолчанию 0 градусов на 3 часах

        g.TranslateTransform(wh.Width, wh.Height)
        g.RotateTransform(t.Second * 6 - 90)
        g.FillPolygon(brush1, psts)

        g.ResetTransform()
        g.TranslateTransform(wh.Width, wh.Height)
        g.RotateTransform(t.Minute * 6 - 90)
        g.FillPolygon(brush1, pmts)

        'стрелку часов рисуем по другому немного, чтобы она зависела от кол-ва минут
        g.ResetTransform()
        g.TranslateTransform(wh.Width, wh.Height)
        g.RotateTransform((t.Hour * 30 - 90) + (t.Minute * 0.5))
        g.FillPolygon(brush1, phts)

        'строка времени для проверки по центру
        g.ResetTransform()
        g.TranslateTransform(wh.Width, wh.Height)
        g.DrawString(t.ToLongTimeString, font1, brush2, -(t.ToLongTimeString.Length * font1.Size * 0.375), j)

        'время
        Me.Text = t.ToLongTimeString & " Часы обыкновенные (c)2004 Denis Egorov, bmp71@yandex.ru"
    End Sub
End Class
