A very simple tkinter analog clock
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 131 132 133 134 135 136 137 | # clock.py By Anton Vredegoor (anton.vredegoor@gmail.com)
# last edit: july 2009,
# license: GPL
# enjoy!
"""
A very simple clock.
The program transforms worldcoordinates into screencoordinates
and vice versa according to an algorithm found in: "Programming
principles in computer graphics" by Leendert Ammeraal.
"""
from Tkinter import *
from time import localtime
from datetime import timedelta,datetime
from math import sin, cos, pi
import sys, types, os
_inidle = type(sys.stdin) == types.InstanceType and \
sys.stdin.__class__.__name__ == 'PyShell'
class transformer:
def __init__(self, world, viewport):
self.world = world
self.viewport = viewport
def point(self, x, y):
x_min, y_min, x_max, y_max = self.world
X_min, Y_min, X_max, Y_max = self.viewport
f_x = float(X_max-X_min) /float(x_max-x_min)
f_y = float(Y_max-Y_min) / float(y_max-y_min)
f = min(f_x,f_y)
x_c = 0.5 * (x_min + x_max)
y_c = 0.5 * (y_min + y_max)
X_c = 0.5 * (X_min + X_max)
Y_c = 0.5 * (Y_min + Y_max)
c_1 = X_c - f * x_c
c_2 = Y_c - f * y_c
X = f * x + c_1
Y = f * y + c_2
return X , Y
def twopoints(self,x1,y1,x2,y2):
return self.point(x1,y1),self.point(x2,y2)
class clock:
def __init__(self,root,deltahours = 0):
self.world = [-1,-1,1,1]
self.bgcolor = '#000000'
self.circlecolor = '#808080'
self.timecolor = '#ffffff'
self.circlesize = 0.09
self._ALL = 'all'
self.pad = 25
self.root = root
WIDTH, HEIGHT = 400, 400
root.bind("<Escape>", lambda _ : root.destroy())
self.delta = timedelta(hours = deltahours)
self.canvas = Canvas(root,
width = WIDTH,
height = HEIGHT,
background = self.bgcolor)
viewport = (self.pad,self.pad,WIDTH-self.pad,HEIGHT-self.pad)
self.T = transformer(self.world,viewport)
self.root.title('Clock')
self.canvas.bind("<Configure>",self.configure())
self.canvas.pack(fill=BOTH, expand=YES)
self.poll()
def configure(self):
self.redraw()
def redraw(self):
sc = self.canvas
sc.delete(self._ALL)
width = sc.winfo_width()
height =sc.winfo_height()
sc.create_rectangle([[0,0],[width,height]],
fill = self.bgcolor, tag = self._ALL)
viewport = (self.pad,self.pad,width-self.pad,height-self.pad)
self.T = transformer(self.world,viewport)
self.paintgrafics()
def paintgrafics(self):
start = -pi/2
step = pi/6
for i in range(12):
angle = start+i*step
x, y = cos(angle),sin(angle)
self.paintcircle(x,y)
self.painthms()
self.paintcircle(0,0)
def painthms(self):
T = datetime.timetuple(datetime.utcnow()-self.delta)
x,x,x,h,m,s,x,x,x = T
self.root.title('%02i:%02i:%02i' %(h,m,s))
angle = -pi/2 + (pi/6)*h + (pi/6)*(m/60.0)
x, y = cos(angle)*.60,sin(angle)*.60
scl = self.canvas.create_line
scl(apply(self.T.twopoints,[0,0,x,y]), fill = self.timecolor,
tag =self._ALL, width = 6)
angle = -pi/2 + (pi/30)*m + (pi/30)*(s/60.0)
x, y = cos(angle)*.80,sin(angle)*.80
scl(apply(self.T.twopoints,[0,0,x,y]), fill = self.timecolor,
tag =self._ALL, width = 3)
angle = -pi/2 + (pi/30)*s
x, y = cos(angle)*.95,sin(angle)*.95
scl(apply(self.T.twopoints, [0,0,x,y]), fill = self.timecolor,
tag =self._ALL, arrow = 'last')
def paintcircle(self,x,y):
ss = self.circlesize / 2.0
mybbox = [-ss+x,-ss+y,ss+x,ss+y]
sco = self.canvas.create_oval
sco(apply(self.T.twopoints,mybbox), fill = self.circlecolor,
tag =self._ALL)
def poll(self):
self.configure()
self.root.after(200,self.poll)
def main():
root= Tk()
# deltahours: how far are you from utc?
# someone should automatize that, but I sometimes want to display
# time as if I am in another timezone ...
clock(root,deltahours = -2)
if not _inidle:
root.mainloop()
if __name__=='__main__':
main()
|
If one has a wide screen, the sides look so empty, and I like analog clocks. One issue is one has to manually edit the code to set the time zone, but that is a feature, not a bug!
Tags: clock
Hi. Great clock :) I believe there might be a bug or two though as it showed the wrong time on my PC.
--JamesMills (prologic)
@James Mills: Was the time off by a round number of hours? If so, you could try adjusting the deltahours knob.
apply()
is deprecated.apply(self.T.twopoints,[0,0,x,y]
should be changed toself.T.twopoints(0,0,x,y)
apply(self.T.twopoints,mybbox)
should be changed toself.T.twopoints(*mybbox)
Really nice piece of coding.
I think your handling of the delta time argument is backwards because timezone offsets values are measured relative to UTC and computed as localtime - UTCtime, which mean you should to add the delta offset to utc to obtain the local value -- not subtract it as done in line 99.
(It's also worth noting that UTC doesn't change with the seasons, and so doesn't observe a daylight saving or summer Time mode that many local times do. This means the
deltahours
value for a local time won't vary either.)In conclusion, it might be easiest to just obtain the local time directly and ignore the
deltahours
argument by replacing line 99 with:Of course the would preclude being able to configure the clock to display some non-local time...
Otherwise, I agree with @Michael, nice work!
Correction: What I said about
deltahours
not needing to vary due to daylight saving / summer time being in effect or not was incorrect -- it may depending on the date and timezone, since UTC itself doesn't observe it.when i ran with geany i got the following error how can i fix it. AttributeError: 'module' object has no attribute 'InstanceType'