3

I have some code for a timer:

from turtle import Screen, Turtle, bgcolor

# --- functions ---

def delSec(string):
    if len(string) == 1:
        return "0" + string
    else:
        return string

def tick():
    global milisecs, ticking


    turtle.clear()

    if milisecs < 0:
        turtle.write("TIMER DONE", align='center', font=FONT)
        ticking = False
        return
    else:
        turtle.write(delSec(str(milisecs//(60*60*10)))+":"+delSec(str((milisecs%(60*60*10))//(60*10)))+":"+delSec(str((milisecs%(60*10))//10))+":"+str(milisecs%10), align='center', font=FONT)
##        turtle.write(delSec(str(milisecs//(60*60)))+":"+delSec(str((milisecs%(60*60))//(60)))+":"+delSec(str((milisecs%(60))//1)), align='center', font=FONT)
        if not paused:
              milisecs -= 1

    screen.ontimer(tick, 100)

def reset():
    global milisecs, ticking, key_reset, key_pause, key_both
    #global paused

    print("reset")

    screen.onkey(None, key_reset)  # Disable event handler inside handler
    screen.onkey(None, key_pause)  # Disable event handler inside handler
    screen.onkey(None, key_both)

    milisecs = sum(time*10)

    if not ticking:
        ticking = True
        tick()

    #paused = False

    screen.onkey(reset, key_reset)  # Reenable event handler
    screen.onkey(pause, key_pause)  # Reenable event handler
    screen.onkey(both, key_both)

def both():
    reset()
    pause()

def pause():
    global paused

    print("pause/unpause")

    paused = not paused

# --- main ---

bgcolor('darkblue')
FONT = ("Arial", 60, "normal")

strings = input("Please enter the time: ").strip().split(' ')

time = [60 ** (len(strings) - index - 1) * int(unit) for index, unit in enumerate(strings)]

milisecs = -1
ticking = False
paused = False
key_reset = "r"
key_pause = "p"
key_both = "b"

screen = Screen()

turtle = Turtle()
turtle.hideturtle()
turtle.color('white')

reset()

screen.listen()
screen.mainloop()

Since it is changing every 10th of a second, it keeps blinking. It is kind of annoying because if I am trying to do something while using this timer, then it gets really annoying. Is there any way to make this smooth instead of constant blinking currently? Thanks! (I have currently set it to where it shows time up to a 10th of a second, and I would like to keep it that way)


EDIT: If you want to change the code, feel free to do so, I would just like it if you would keep the current functions the same, so don't make it so something else doesn't work anymore. Thanks!

Mike Smith
  • 527
  • 2
  • 6
  • 20
  • `turtle.speed(0)` might prevent the display being updated between clearing the screen and redrawing the updated timer. – jasonharper Feb 20 '20 at 20:12
  • The blinking is still happening. I think maybe some calculations are using up some time. I'm open to slightly different approaches to how to code it... – Mike Smith Feb 21 '20 at 01:40
  • Are you actually planning on using the graphical capabilities of turtles in your program? Changing existing things on the screen is just not something that fits well into the turtle graphics paradigm. If you'd be willing to switch to a different approach, there are numerous options that can do this kind of thing trivially. (The `tkinter` library that `turtle` is based on, for one). – jasonharper Feb 21 '20 at 01:52
  • I don't mind what approach I use, but I am very inexperienced in choosing my approach to a problem. As long as the final result is the same, or in this case better, since my current result is not what I want, I am happy. My only restriction is that I want to use Python. – Mike Smith Feb 21 '20 at 02:05

1 Answers1

1

I've changed your (actually our) code minimally to get rid of flicker by introducing the tracer() and update() screen methods. This tells turtle that we know best when to (manually) update the screen and stop doing so automatically:

from turtle import Screen, Turtle

# --- constants ---

FONT = ("Arial", 60, "normal")

KEY_RESET = "r"
KEY_PAUSE = "p"
KEY_BOTH = "b"

# --- functions ---

def delSec(string):
    if len(string) == 1:
        return "0" + string

    return string

def tick():
    global milisecs, ticking

    turtle.clear()

    if milisecs < 0:
        turtle.write("TIMER DONE", align='center', font=FONT)
        screen.update()
        ticking = False
        return

    turtle.write( \
        delSec(str(milisecs // (60*60*10))) + ":" + \
        delSec(str((milisecs % (60*60*10)) // (60*10))) + ":" + \
        delSec(str((milisecs % (60*10)) // 10)) + "." + \
        str(milisecs % 10), align='center', font=FONT)

    screen.update()

    if not paused:
        milisecs -= 1

    screen.ontimer(tick, 100)

def reset():
    global milisecs, ticking

    print("reset")

    screen.onkey(None, KEY_RESET)  # Disable event handler inside handler
    screen.onkey(None, KEY_PAUSE)  # Disable event handler inside handler
    screen.onkey(None, KEY_BOTH)

    milisecs = sum(time*10)

    if not ticking:
        ticking = True
        tick()

    screen.onkey(reset, KEY_RESET)  # Reenable event handler
    screen.onkey(pause, KEY_PAUSE)  # Reenable event handler
    screen.onkey(both, KEY_BOTH)

def both():
    reset()
    pause()

def pause():
    global paused

    print("pause/unpause")

    paused = not paused

# --- main ---

strings = input("Please enter the time: ").strip().split(' ')

time = [60 ** (len(strings) - index - 1) * int(unit) for index, unit in enumerate(strings)]

milisecs = -1
ticking = False
paused = False

screen = Screen()
screen.bgcolor('darkblue')
screen.tracer(False)

turtle = Turtle()
turtle.hideturtle()
turtle.color('white')

reset()

screen.listen()
screen.mainloop()

I also made some small code tweaks as well as change the tenths of seconds presentation from being "45:7" to more standardized "45.7". Revert as you see fit.

cdlane
  • 40,441
  • 5
  • 32
  • 81