]>
Commit | Line | Data |
---|---|---|
1 | #---------------------------------------------------------------------- | |
2 | # Name: wxPython.lib.analogclock | |
3 | # Purpose: A simple analog clock window | |
4 | # | |
5 | # Author: several folks on wxPython-users | |
6 | # | |
7 | # Created: 16-April-2003 | |
8 | # RCS-ID: $Id$ | |
9 | # Copyright: (c) 2003 by Total Control Software | |
10 | # Licence: wxWindows license | |
11 | #---------------------------------------------------------------------- | |
12 | # 11/30/2003 - Jeff Grimmett (grimmtooth@softhome.net) | |
13 | # | |
14 | # o Updated for wx namespace | |
15 | # o Tested with updated demo and with builtin test. | |
16 | # | |
17 | ||
18 | import math | |
19 | import string | |
20 | import sys | |
21 | import time | |
22 | ||
23 | import wx | |
24 | ||
25 | class AnalogClockWindow(wx.Window): | |
26 | """A simple analog clock window""" | |
27 | ||
28 | TICKS_NONE = 0 | |
29 | TICKS_SQUARE = 1 | |
30 | TICKS_CIRCLE = 2 | |
31 | ||
32 | def __init__(self, parent, ID=-1, pos=wx.DefaultPosition, size=wx.DefaultSize, | |
33 | style=0, name="clock"): | |
34 | ||
35 | # Initialize the wxWindow... | |
36 | wx.Window.__init__(self, parent, ID, pos, size, style, name) | |
37 | ||
38 | # Initialize the default clock settings... | |
39 | self.minuteMarks = 60 | |
40 | self.hourMarks = 12 | |
41 | self.tickMarksBrushC = self.GetForegroundColour() | |
42 | self.tickMarksPenC = self.GetForegroundColour() | |
43 | self.tickMarkStyle = self.TICKS_SQUARE | |
44 | ||
45 | # Make an initial bitmap for the face, it will be updated and | |
46 | # painted at the first EVT_SIZE event. | |
47 | W, H = size | |
48 | self.faceBitmap = wx.EmptyBitmap(max(W,1), max(H,1)) | |
49 | ||
50 | # Initialize the timer that drives the update of the clock | |
51 | # face. Update every half second to ensure that there is at | |
52 | # least one true update during each realtime second. | |
53 | self.timer = wx.Timer(self) | |
54 | self.timer.Start(500) | |
55 | ||
56 | # Set event handlers... | |
57 | self.Bind(wx.EVT_PAINT, self.OnPaint) | |
58 | self.Bind(wx.EVT_ERASE_BACKGROUND, lambda x: None) | |
59 | self.Bind(wx.EVT_SIZE, self.OnSize) | |
60 | self.Bind(wx.EVT_TIMER, self.OnTimerExpire) | |
61 | self.Bind(wx.EVT_WINDOW_DESTROY, self.OnQuit) | |
62 | ||
63 | ||
64 | def SetTickMarkStyle(self, style): | |
65 | """ | |
66 | Set the style of the marks around the edge of the clock. | |
67 | Options are TICKS_NONE, TICKS_SQUARE, and TICKS_CIRCLE | |
68 | """ | |
69 | self.tickMarkStyle = style | |
70 | ||
71 | ||
72 | def SetTickMarkColours(self, brushC, penC="BLACK"): | |
73 | """ | |
74 | Set the brush colour and optionally the pen colour of | |
75 | the marks around the edge of the clock. | |
76 | """ | |
77 | self.tickMarksBrushC = brushC | |
78 | self.tickMarksPenC = penC | |
79 | ||
80 | SetTickMarkColour = SetTickMarkColours | |
81 | ||
82 | ||
83 | def SetHandsColour(self, c): | |
84 | """An alias for SetForegroundColour""" | |
85 | self.SetForegroundColour(c) # the hands just use the foreground colour | |
86 | ||
87 | ||
88 | # Using the current settings, render the points and line endings for the | |
89 | # circle inside the specified device context. In this case, the DC is | |
90 | # a memory based device context that will be blitted to the actual | |
91 | # display DC inside the OnPaint() event handler. | |
92 | def OnSize(self, event): | |
93 | # The faceBitmap init is done here, to make sure the buffer is always | |
94 | # the same size as the Window | |
95 | size = self.GetClientSize() | |
96 | self.faceBitmap = wx.EmptyBitmap(size.width, size.height) | |
97 | self.DrawFace() | |
98 | ||
99 | ||
100 | def OnPaint(self, event): | |
101 | self.DrawHands(wx.PaintDC(self)) | |
102 | ||
103 | ||
104 | def OnQuit(self, event): | |
105 | self.timer.Stop() | |
106 | del self.timer | |
107 | ||
108 | ||
109 | def OnTimerExpire(self, event): | |
110 | self.DrawHands(wx.ClientDC(self)) | |
111 | ||
112 | ||
113 | def DrawHands(self, drawDC): | |
114 | # Start by drawing the face bitmap | |
115 | drawDC.DrawBitmap(self.faceBitmap, (0,0)) | |
116 | ||
117 | currentTime = time.localtime(time.time()) | |
118 | hour, minutes, seconds = currentTime[3:6] | |
119 | ||
120 | W,H = self.faceBitmap.GetWidth(), self.faceBitmap.GetHeight() | |
121 | centerX = W / 2 | |
122 | centerY = H / 2 | |
123 | ||
124 | radius = min(centerX, centerY) | |
125 | hour += minutes / 60.0 # added so the hour hand moves continuously | |
126 | x, y = self.point(hour, 12, (radius * .65)) | |
127 | hourX, hourY = (x + centerX), (centerY - y) | |
128 | x, y = self.point(minutes, 60, (radius * .85)) | |
129 | minutesX, minutesY = (x + centerX), (centerY - y) | |
130 | x, y = self.point(seconds, 60, (radius * .85)) | |
131 | secondsX, secondsY = (x + centerX), (centerY - y) | |
132 | ||
133 | # Draw the hour hand... | |
134 | drawDC.SetPen(wx.Pen(self.GetForegroundColour(), 5, wx.SOLID)) | |
135 | drawDC.DrawLine((centerX, centerY), (hourX, hourY)) | |
136 | ||
137 | # Draw the minutes hand... | |
138 | drawDC.SetPen(wx.Pen(self.GetForegroundColour(), 3, wx.SOLID)) | |
139 | drawDC.DrawLine((centerX, centerY), (minutesX, minutesY)) | |
140 | ||
141 | # Draw the seconds hand... | |
142 | drawDC.SetPen(wx.Pen(self.GetForegroundColour(), 1, wx.SOLID)) | |
143 | drawDC.DrawLine((centerX, centerY), (secondsX, secondsY)) | |
144 | ||
145 | ||
146 | # Draw the specified set of line marks inside the clock face for the | |
147 | # hours or minutes... | |
148 | def DrawFace(self): | |
149 | backgroundBrush = wx.Brush(self.GetBackgroundColour(), wx.SOLID) | |
150 | drawDC = wx.MemoryDC() | |
151 | drawDC.SelectObject(self.faceBitmap) | |
152 | drawDC.SetBackground(backgroundBrush) | |
153 | drawDC.Clear() | |
154 | ||
155 | W,H = self.faceBitmap.GetWidth(), self.faceBitmap.GetHeight() | |
156 | centerX = W / 2 | |
157 | centerY = H / 2 | |
158 | ||
159 | # Draw the marks for hours and minutes... | |
160 | self.DrawTimeMarks(drawDC, self.minuteMarks, centerX, centerY, 4) | |
161 | self.DrawTimeMarks(drawDC, self.hourMarks, centerX, centerY, 9) | |
162 | ||
163 | ||
164 | def DrawTimeMarks(self, drawDC, markCount, centerX, centerY, markSize): | |
165 | for i in range(markCount): | |
166 | x, y = self.point(i + 1, markCount, min(centerX,centerY) - 16) | |
167 | scaledX = x + centerX - markSize/2 | |
168 | scaledY = centerY - y - markSize/2 | |
169 | ||
170 | drawDC.SetBrush(wx.Brush(self.tickMarksBrushC, wx.SOLID)) | |
171 | drawDC.SetPen(wx.Pen(self.tickMarksPenC, 1, wx.SOLID)) | |
172 | ||
173 | if self.tickMarkStyle != self.TICKS_NONE: | |
174 | if self.tickMarkStyle == self.TICKS_CIRCLE: | |
175 | drawDC.DrawEllipse((scaledX - 2, scaledY), (markSize, markSize)) | |
176 | else: | |
177 | drawDC.DrawRectangle((scaledX - 3, scaledY), (markSize, markSize)) | |
178 | ||
179 | ||
180 | def point(self, tick, range, radius): | |
181 | angle = tick * (360.0 / range) | |
182 | radiansPerDegree = math.pi / 180 | |
183 | pointX = int(round(radius * math.sin(angle * radiansPerDegree))) | |
184 | pointY = int(round(radius * math.cos(angle * radiansPerDegree))) | |
185 | return wx.Point(pointX, pointY) | |
186 | ||
187 | ||
188 | ||
189 | ||
190 | if __name__ == "__main__": | |
191 | class App(wx.App): | |
192 | def OnInit(self): | |
193 | frame = wx.Frame(None, -1, "AnalogClockWindow Test", size=(375,375)) | |
194 | ||
195 | clock = AnalogClockWindow(frame) | |
196 | clock.SetTickMarkColours("RED") | |
197 | clock.SetHandsColour("WHITE") | |
198 | clock.SetBackgroundColour("BLUE") | |
199 | ||
200 | frame.Centre(wx.BOTH) | |
201 | frame.Show(True) | |
202 | self.SetTopWindow(frame) | |
203 | return True | |
204 | ||
205 | theApp = App(0) | |
206 | theApp.MainLoop() | |
207 | ||
208 | ||
209 |