I have to create an analog clock using winforms in F#. The clock needs also to have a label showing date and time in digital form. I have figured how make the label with time and date, as well as drawing the circle and the clockhands, but I'm having trouble with how i'm gonna implement the timer function to the clock hands. So they move, and move to what the time is right now.
I don't know how to call the things i need in the third last line. Is there anyone who can help me with this problem? Because as it stands right now I have no idea how to it.
open System
open System.Windows.Forms
open System.ComponentModel
open System.Drawing
// ********* Winforms specifics *********
let win = new Form()
win.ClientSize <- Size (400, 400)
/// ********* Working Digital Clock *********
// make a label to show time
let digitalTimerLabel = new Label ()
win.Controls.Add digitalTimerLabel
digitalTimerLabel.Width <- 200
digitalTimerLabel.Location <- new Point (140,300)
digitalTimerLabel.Text <- string System.DateTime.Now // get present time and date
// make a timer and link to label
let timer = new Timer ()
timer.Interval <- 1000 // create an event every 1000 millisecond
timer.Enabled <- true // activiate the timer
timer.Tick.Add (fun e ->
digitalTimerLabel.Text <- string System.DateTime.Now
win.Invalidate()
)
// ********* Translate the clock *********
let translate (d : Point) (arr : Point []) : Point [] =
let add (d : Point) (p : Point) : Point =
Point (d.X + p.X, d.Y + p.Y)
Array.map (add d) arr
// ********* Rotate the clock hands *********
let rotate (theta : float) (arr : Point []) : Point [] =
let toInt = int << round
let rot (t : float) (p : Point) : Point =
let (x, y) = (float p.X, float p.Y)
let (a, b) = (x * cos t - y * sin t, x * sin t + y * cos t)
Point (toInt a, toInt b)
Array.map (rot theta) arr
/// ********* ClockHands (Ur-visere) *********
let myPaint (e : PaintEventArgs) : unit =
// HourHand
let black = new Pen (Color.Black,Width=2.0f)
let hourHand =
// [bot cord] [top cord]
[|Point (0,0);Point (0,-45)|]
e.Graphics.DrawLines (black, hourHand)
// MinuteHand
let red = new Pen (Color.Red,Width=4.0f)
let minuteHand =
// [bot cord] [top cord]
[|Point (0,0);Point (0,-20)|]
e.Graphics.DrawLines (red, minuteHand)
// SecondHand
let green = new Pen (Color.Green,Width=1.0f)
let secondHand =
// [bot cord] [top cord]
[|Point (0,0);Point (0,-20)|]
e.Graphics.DrawLines (green, secondHand)
// Circle
let circleBlack = new Pen(Color.Black,Width=4.0f)
let circle =
e.Graphics.DrawEllipse(circleBlack,-100.0f,-100.0f,200.0f,200.0f)
circle
// CenterDot
let CenterDotBrush = new SolidBrush(Color.Red)
let center =
e.Graphics.FillEllipse(CenterDotBrush,-2.5f,-2.5f,5.0f,5.0f)
center
let dt = DateTime.Now
let s = dt.Second
let m = dt.Minute
let h = dt.Hour
let newS = rotate (float s/60.0*2.0*System.Math.PI) secondHand
let newM = rotate (float m/60.0*2.0*System.Math.PI) minuteHand
let newH = rotate (float h/12.0*2.0*System.Math.PI) hourHand
let finalS = translate (Point (200, 200)) secondHand
let finalM = translate (Point (200, 200)) minuteHand
let finalH = translate (Point (200, 200)) hourHand
()
win.Paint.Add myPaint
Application.Run win // start event - loop
I have sorted it out. It works now:
open System
open System.Windows.Forms
open System.Drawing
// ********* Winforms specifics *********
// Extended the default Form to avoid display flickered
type SmoothForm() as x =
inherit Form()
do x.DoubleBuffered <- true
let win = new SmoothForm()
win.ClientSize <- Size (400, 400)
/// ********* Digital Clock *********
// make a label to show time
let digitalTimerLabel = new Label ()
win.Controls.Add digitalTimerLabel
digitalTimerLabel.Width <- 200
digitalTimerLabel.Location <- Point (150,320)
// Timer
let timer = new Timer ()
timer.Interval <- 1000 // create an event every 1000 millisecond
timer.Enabled <- true // activiate the timer
timer.Tick.Add (fun _e ->
digitalTimerLabel.Text <- string System.DateTime.Now
win.Invalidate()
)
// ********* Translate function *********
let translate (d : Point) (arr : Point []) : Point [] =
let add (d : Point) (p : Point) : Point =
Point (d.X + p.X, d.Y + p.Y)
Array.map (add d) arr
// ********* Rotate the clock hands *********
let rotate (theta : float) (arr : Point []) : Point [] =
let toInt = int << round
let rot (t : float) (p : Point) : Point =
let (x, y) = (float p.X, float p.Y)
let (a, b) = (x * cos t - y * sin t, x * sin t + y * cos t)
Point (toInt a, toInt b)
Array.map (rot theta) arr
/// ********* ClockHands (Ur-visere) *********
let myPaint (e : PaintEventArgs) : unit =
// HourHand
let black = new Pen (Color.Black,Width=4.0f)
let hourHand =
[|Point (0,0); Point (0,-60)|]
// MinuteHand
let red = new Pen (Color.Red,Width=4.0f)
let minuteHand =
[|Point (0,0);Point (0,-90)|]
// SecondHand
let green = new Pen (Color.Green,Width=1.0f)
let secondHand =
[|Point (0,0);Point (0,-90)|]
// Circle
let circleBlack = new Pen(Color.Black,Width=4.0f)
let circle =
e.Graphics.DrawEllipse(circleBlack,100.0f,100.0f,200.0f,200.0f)
circle
//Circle color
let circlecolorBrush = new SolidBrush(Color.LightSalmon)
let circle =
e.Graphics.FillEllipse(circlecolorBrush,100.0f,100.0f,200.0f,200.0f)
circle
// CenterDot
let centerDotBrush = new SolidBrush(Color.Red)
let center =
e.Graphics.FillEllipse(centerDotBrush,197.5f,197.5f,5.0f,5.0f)
center
// Time
let dt = DateTime.Now
let s = dt.Second
let m = dt.Minute
let h = dt.Hour
// Make Rotation
let secondHand = rotate (float s/60.0*2.0*System.Math.PI) secondHand
let minuteHand = rotate (float m/60.0*2.0*System.Math.PI) minuteHand
let hourHand = rotate (float h/12.0*2.0*System.Math.PI) hourHand
// Make Translate (Moving Point)
let secondHand = translate (Point (200, 200)) secondHand
let minuteHand = translate (Point (200, 200)) minuteHand
let hourHand = translate (Point (200, 200)) hourHand
e.Graphics.DrawLines (black, hourHand)
e.Graphics.DrawLines (red, minuteHand)
e.Graphics.DrawLines (green, secondHand)
win.Paint.Add myPaint
Application.Run win // start event - loop