WPF clock

Ruby code posted by Edd Morgan
created at 12 Jun 00:17

Edit | Back
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
require 'WindowsBase'
require 'PresentationFramework'
require 'PresentationCore'
require 'System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'

class Clock

    CLOCK_WIDTH     = 150
    CLOCK_HEIGHT    = 150
    LABEL_HEIGHT    = CLOCK_HEIGHT / 7
    LABEL_WIDTH     = CLOCK_WIDTH / 7
    RADIUS          = CLOCK_WIDTH / 2
    RADS            = Math::PI / 180
    MIN_LOCATIONS   = {}
    HOUR_LOCATIONS  = {}

    def run!
        plot_locations

        # build our window
        @window = System::Windows::Window.new
        @window.background = System::Windows::Media::Brushes.LightGray
        @window.width = CLOCK_WIDTH * 2
        @window.height = CLOCK_HEIGHT * 2
        @window.resize_mode = System::Windows::ResizeMode.NoResize
        
        @canvas = System::Windows::Controls::Canvas.new
        @canvas.width = CLOCK_WIDTH
        @canvas.height = CLOCK_HEIGHT

        # create shapes to represent clock hands
        @minute_hand = System::Windows::Shapes::Line.new
        @minute_hand.stroke = System::Windows::Media::Brushes.Black
        @minute_hand.stroke_thickness = 1
        @minute_hand.x1 = CLOCK_WIDTH / 2
        @minute_hand.y1 = CLOCK_HEIGHT / 2

        @hour_hand = System::Windows::Shapes::Line.new
        @hour_hand.stroke = System::Windows::Media::Brushes.Black
        @hour_hand.stroke_thickness = 3
        @hour_hand.x1 = CLOCK_WIDTH / 2
        @hour_hand.y1 = CLOCK_HEIGHT / 2
        
        # .. and stick them to our canvas
        @canvas.children.add(@minute_hand)
        @canvas.children.add(@hour_hand)
        
        plot_face # draw a clock face
        plot_labels # draw clock numbers
        plot_hands # draw minute / hour hands

        @window.content = @canvas
        app = System::Windows::Application.new
        app.run(@window)
        # the Application object handles the lifecycle of our app
        # including the execution loop
    end
    
    # determine 2 sets of equidistant points around the circumference of a circle
    # of CLOCK_WIDTH and CLOCK_HEIGHT dimensions.
    def plot_locations
        for i in (0..60) # 60 minutes, and 12 hours
            a = i * 6
            x = (RADIUS * Math.sin(a * RADS)).to_i + (CLOCK_WIDTH / 2)
            y = (CLOCK_HEIGHT / 2) - (RADIUS * Math.cos(a * RADS)).to_i
            coords = [x, y]
            HOUR_LOCATIONS[i / 5] = coords if i % 5 == 0 # is this also an 'hour' location (ie. every 5 minutes)?
            MIN_LOCATIONS[i] = coords
        end
    end
    
    # draws a circle to represent the clock's face
    def plot_face
        extra_x = (CLOCK_WIDTH * 0.15) # pad our circle a little
        extra_y = (CLOCK_HEIGHT * 0.15)
        face = System::Windows::Shapes::Ellipse.new
        face.fill = System::Windows::Media::Brushes.White
        face.width = CLOCK_WIDTH + extra_x
        face.height = CLOCK_HEIGHT + extra_y
        face.margin = System::Windows::Thickness.new(0 - (extra_x/2), 0 - (extra_y/2), 0, 0)
        face.stroke = System::Windows::Media::Brushes.Gray # give it a slight border
        face.stroke_thickness = 1 
        System::Windows::Controls::Canvas.set_z_index(face, -1) # send our circle to the back
        @canvas.children.add(face) # add the clock face to our canvas
    end
    
    # at each point along the hour locations, put a number
    def plot_labels
        HOUR_LOCATIONS.each_pair do |p, coords|
            unless p == 0
                lbl = System::Windows::Controls::Label.new
                lbl.horizontal_content_alignment = System::Windows::HorizontalAlignment.Center
                lbl.width = LABEL_WIDTH
                lbl.height = LABEL_HEIGHT
                lbl.content = p.to_s
                lbl.margin = System::Windows::Thickness.new(coords[0] - (LABEL_WIDTH / 2), coords[1] - (LABEL_HEIGHT / 2), 0, 0)
                lbl.padding = System::Windows::Thickness.new(0, 0, 0, 0)
                @canvas.children.add(lbl)
            end
        end
    end
    
    def plot_hands
        time = Time.now
        hours = time.hour
        minutes = time.min
        
        if !@minutes || minutes != @minutes
            @hours = hours >= 12 ? hours - 12 : hours
            @minutes = minutes == 0 ? 60 : minutes
            # Dispatcher.BeginInvoke() is asynchronous, though it probably doesn't matter too much here
            @minute_hand.dispatcher.begin_invoke(System::Windows::Threading::DispatcherPriority.Render, System::Action.new {
                @minute_hand.x2 = MIN_LOCATIONS[@minutes][0]
                @minute_hand.y2 = MIN_LOCATIONS[@minutes][1]
                @hour_hand.x2 = HOUR_LOCATIONS[@hours][0]
                @hour_hand.y2 = HOUR_LOCATIONS[@hours][1]
            })
        end
    end
    
end

clock = Clock.new

timer = System::Timers::Timer.new
timer.interval = 1000
timer.elapsed { clock.plot_hands }
timer.enabled = true

clock.run!
4.92 KB in 6 ms with coderay