Once the dial is ready with all markings ( read part 1 , creating dial ), to this we will add needles to the clock.
Analog clock in Tkinter Canvas with three needles hour, minute, second initializing with local time
Following points may be noted.
Each segment is 6 degree and there are 60 segments in our dial.
Each needle has to increase by 6 degree to cross one segment.
For each 360 degree rotation of second needle, minute needle will move by one segment ( 6 degree ).
Hour needle moves 30 degree or 5 segments of 6 degree each on every completion of one rotation of 360 degree by minutes needle.
Zero degree is the 12 O’clock position.
We will use three functions my_second(),my_minute() and my_hour() to display and rotate needles. Using timer we will call ( recursive call ) to my_second() function and on completion of 360 degree we will trigger my_minute() function and on completion of 360 degree of minute needle we will call my_hour().
Increment in each call to functions
Second needle has to increase by one segment of 6 degree on each call to my_second() function ( on every second ).
Minute needle has to increase by one segment of 6 degree on each call to my_minute() function. ( on every 60 seconds).
Hour needle has to increase by 0.5 degree on each call to my_hour() function.
Starting angles of Hour minute and second needles
When the clock starts, we must read the local time and accordingly shift the needles ( starting point). From this point we can start moving the needles. Here is how to read the local time in hour minutes and seconds.
in_degree = 0 # for creating dial markings
in_degree_s=int(time.strftime('%S')) *6 # local second
in_degree_m=int(time.strftime('%M'))*6 # local minutes
in_degree_h=int(time.strftime('%I')) * 30 # 12 hour format
print(in_degree_h)
Initializing second needle position based on local time
Our variable in_degree_s will hold the local second value.
in_radian = math.radians(in_degree_s)
x2=x+rs*math.sin(in_radian)
y2=y-rs*math.cos(in_radian)
second=c1.create_line(x,y,x2,y2,fill='red',width=2) # draw the needle
Above code will draw the second needle based on the local time second value and the variable in_degree_s will hold the degree based on this local time value.
Rotating Second needle my_second()
As we have initialized the variable in_degree_s based on the local time value of seconds, we will use these variables as global and create the function my_second()
Use of timer
We used one timer which calls the same function ( recursive ) my_second after 1000 milliseconds (= 1 second ).
c1.after(1000,my_second)
Each call to this function will move the second needle by 6 degree ( in_degree_s=in_degree_s+6 )
The movement of second needle is achieved by deleting the second needle and redrawing it at the new coordinates.
c1.delete(second) # delete the needle
x2=x+rs*math.sin(in_radian) # Horizontal coordinate of outer edge.
y2=y-rs*math.cos(in_radian) # vertical coordinate of outer adge
second=c1.create_line(x,y,x2,y2,arrow='last',fill='red',width=2)
Full code for movement of Second needle is here .
def my_second():
global in_degree_s,second
in_radian = math.radians(in_degree_s) # from degree to ra
c1.delete(second) # delete the needle
x2=x+rs*math.sin(in_radian) # Horizontal coordinate of outer edge.
y2=y-rs*math.cos(in_radian) # vertical coordinate of outer adge
second=c1.create_line(x,y,x2,y2,arrow='last',fill='red',width=2)
if(in_degree_s>=360): # one rotattion is over if reached 360
in_degree_s=0 # start from zero angle again
my_minute() # call the minute needle to move one segment.
in_degree_s=in_degree_s+6 # increment of one segment is 6 degree
c1.after(1000,my_second) # recursive call after 1000 milliseconds
Minute needle
Each complete rotation of second needle will trigger the my_miute() function. Check the lines in above code( inside my_second() function ).
if(in_degree_s>=360): # one rotattion is over if reached 360
in_degree_s=0 # start from zero angle again
my_minute() # call the minute needle to move one segment.
c1.after(1000,my_second) # recursive call after 1000 milliseconds
Adjusting minute needle based on initial minutes value
The variable in_degree_m will hold the angle for minutes needle after reading the local time minute value. ( check the starting angles of hour , minute and second needles above )
def my_minute():
global in_degree_m,minute
in_degree_m=in_degree_m+6 # increment for each segment
in_radian = math.radians(in_degree_m) # converting to radians
c1.delete(minute) # delete the previous needle
x2=x+rm*math.sin(in_radian) # Horizontal coordinate of outer edge.
y2=y-rm*math.cos(in_radian) # vertical coordinate of outer dege
minute=c1.create_line(x,y,x2,y2,width=4,fill='green')
my_hour() # calling hour needle to move
if(in_degree_m>=360): # One rotation of 360 degree is over
in_degree_m=0
Adjusting hour needle based on initial minutes value
At the starting, hour needle we have to move fraction of one hour based on the minutes value. When local time is 7.45 , the hour needle has to be 3/4 of 7 hour and 8 hour segments.
Note that for 360 degree rotation of minute ( one hour ) the hour needle moves by 30 degree. To get the initial angle for hour needle we have to multiply minutes angle value like this. Here 30/360 = 0.0833333