Home > Back-end >  Can't get turtle ontimer() function working
Can't get turtle ontimer() function working

Time:11-27

I can't get turtle ontimer() function working.

When I use the ontimer function of the turtle library the code executes directly and does not wait for the expected time.

To make my code work I used the function time.sleep(1) which is not a great solution

Here is the code:

import turtle, time

heure_=int(input("Enter the time in hh format: "))
minute_=int(input("Enter the minutes in mm format: "))
seconde_=int(input("Enter the seconds in ss format: "))

#calculate time
def formt(h, m, s):
    minute, seconde = divmod(s, 60)
    heure, minute = divmod(minute m, 60)
    heure = (heure h)%12
    return heure, minute, seconde

heure, minute, seconde = formt(heure_, minute_, seconde_)
#function to calculate hands angles
def angle(h, m, s):
    angle_s=(360 / 60) * s
    angle_m=(360 / 60) * m   angle_s*1/60
    angle_h=(360 / 12) * h   angle_m*1/12
    return angle_h, angle_m, angle_s

#hands
def aigh(h, x=0, y=0, f=100):
    hour_t.ht()
    hour_t.goto(x,y)
    hour_t.setheading(90)
    hour_t.rt(h)
    hour_t.pendown()
    hour_t.width(10)
    hour_t.forward(f)

def aigm(m, x=0, y=0, f=150):
    min_t.ht()
    min_t.goto(x,y)
    min_t.setheading(90)
    min_t.rt(m)
    min_t.pendown()
    min_t.width(5)
    min_t.forward(f)

def aigs(s, x=0, y=0, f=170):
    sec_t.ht()
    sec_t.goto(x,y)
    sec_t.setheading(90)
    sec_t.color("red")
    sec_t.width()
    sec_t.rt(s)
    sec_t.pendown()
    sec_t.width(1)
    sec_t.forward(f)

#init turtle
t = turtle.Turtle()

#turtles for hands
hour_t = turtle.Turtle()
min_t = turtle.Turtle()
sec_t = turtle.Turtle()

wn = turtle.Screen()
wn.title("Clock")

wn.tracer(0)

def draw(h, m, s):
    aigh(h)
    aigm(m)
    aigs(s)
    
def refresh(h=heure, m=minute, s=seconde):
    global seconde
    wn.tracer(0)
    hour_t.undo()
    min_t.undo()
    sec_t.undo()
    
    h_, m_, s_ = formt(h, m, s)
    t.undo()
    
    #get the hands angles
    agl_h, agl_m, agl_s = angle(h_, m_, s_)

    #draw the hands
    draw(agl_h, agl_m, agl_s)

    wn.update()
    
    seconde  =1

    #wn.ontimer(refresh, 1000)

for _ in iter(int, 1):
    refresh(s=seconde)
    time.sleep(1)

How can i make the code work ? Thank you.

CodePudding user response:

You have fallen into one of the classic Python traps. When you say this:

def refresh(h=heure, m=minute, s=seconde):

The default values are captured at the time the function is defined. Those are not live values. So, if you enter 5, 15, 23, the default values for those parameters will ALWAYS be 5, 15 and 23, regardless of how the globals change.

You are totally dependent on the globals here, so just use them. This works:

import turtle, time

heure_=int(input("Enter the time in hh format: "))
minute_=int(input("Enter the minutes in mm format: "))
seconde_=int(input("Enter the seconds in ss format: "))

#calculate time
def formt(h, m, s):
    minute, seconde = divmod(s, 60)
    heure, minute = divmod(minute m, 60)
    heure = (heure h)%12
    return heure, minute, seconde

heure, minute, seconde = formt(heure_, minute_, seconde_)
#function to calculate hands angles
def angle(h, m, s):
    angle_s=(360 / 60) * s
    angle_m=(360 / 60) * m   angle_s*1/60
    angle_h=(360 / 12) * h   angle_m*1/12
    return angle_h, angle_m, angle_s

#hands
def aigh(h, x=0, y=0, f=100):
    hour_t.ht()
    hour_t.goto(x,y)
    hour_t.setheading(90)
    hour_t.rt(h)
    hour_t.pendown()
    hour_t.width(10)
    hour_t.forward(f)

def aigm(m, x=0, y=0, f=150):
    min_t.ht()
    min_t.goto(x,y)
    min_t.setheading(90)
    min_t.rt(m)
    min_t.pendown()
    min_t.width(5)
    min_t.forward(f)

def aigs(s, x=0, y=0, f=170):
    sec_t.ht()
    sec_t.goto(x,y)
    sec_t.setheading(90)
    sec_t.color("red")
    sec_t.width()
    sec_t.rt(s)
    sec_t.pendown()
    sec_t.width(1)
    sec_t.forward(f)

#init turtle
t = turtle.Turtle()

#turtles for hands
hour_t = turtle.Turtle()
min_t = turtle.Turtle()
sec_t = turtle.Turtle()

wn = turtle.Screen()
wn.title("Clock")

wn.tracer(0)

def draw(h, m, s):
    aigh(h)
    aigm(m)
    aigs(s)
    
def refresh():
    global seconde
    wn.tracer(0)
    hour_t.undo()
    min_t.undo()
    sec_t.undo()
    
    h_, m_, s_ = formt(heure, minute, seconde)
    t.undo()
    
    #get the hands angles
    agl_h, agl_m, agl_s = angle(h_, m_, s_)

    #draw the hands
    draw(agl_h, agl_m, agl_s)

    wn.update()
    
    seconde  =1

while True:
    refresh()
    time.sleep(1)

CodePudding user response:

I see a number of small issues with your code (e.g. the hands don't take on their assigned widths and colors.) I agree with @TimRoberts that default arguments are your primary issue. Below is my rework of the code to use ontimer() and attempt to both fix and simplify it:

from turtle import Screen, Turtle

heure_ = int(input("Enter the time in hh format: "))
minute_ = int(input("Enter the minutes in mm format: "))
seconde_ = int(input("Enter the seconds in ss format: "))

# calculate time
def formt(h, m, s):
    minute, seconde = divmod(s, 60)
    heure, minute = divmod(minute   m, 60)
    heure = (heure   h) % 12

    return heure, minute, seconde

# function to calculate hands angles
def angle(h, m, s):
    angle_s = (360 / 60) * s
    angle_m = (360 / 60) * m   angle_s/60
    angle_h = (360 / 12) * h   angle_m/12

    return angle_h, angle_m, angle_s

# hands
def aigh(h, x=0, y=0, f=100):
    hour_t.goto(x, y)
    hour_t.clear()
    hour_t.setheading(h)
    hour_t.forward(f)

def aigm(m, x=0, y=0, f=150):
    min_t.goto(x, y)
    min_t.clear()
    min_t.setheading(m)
    min_t.forward(f)

def aigs(s, x=0, y=0, f=170):
    sec_t.goto(x, y)
    sec_t.clear()
    sec_t.setheading(s)
    sec_t.forward(f)

def draw(h, m, s):
    aigh(h)
    aigm(m)
    aigs(s)

heure, minute, seconde = formt(heure_, minute_, seconde_)

def refresh():
    global heure, minute, seconde

    heure, minute, seconde = formt(heure, minute, seconde)

    # get the hands angles
    agl_h, agl_m, agl_s = angle(heure, minute, seconde)

    # draw the hands
    draw(agl_h, agl_m, agl_s)

    seconde  = 1

    screen.update()

    screen.ontimer(refresh, 1000)

screen = Screen()
screen.mode('logo')  # 0 degrees at top, circles go clockwise, like a clock!
screen.title("Clock")
screen.tracer(False)

# turtles for hands
hour_t = Turtle()
hour_t.hideturtle()
hour_t.width(10)

min_t = Turtle()
min_t.hideturtle()
min_t.width(5)

sec_t = Turtle()
sec_t.hideturtle()
sec_t.width(1)
sec_t.color("red")

refresh()

screen.mainloop()
  • Related