I’m trying to use python 3 turtle graphics to do something like presentation software: draw something, pause for a keystroke so the presenter can explain, then draw the next thing.
Here is one solution I’ve tried (that doesn’t work):
import turtle
import time
paused = False
def unpause():
print("unpause() called")
global paused
paused = False
def pause():
global paused
paused = True
while paused:
time.sleep(0.1)
t = turtle.Turtle()
# set up listener
t.screen.listen()
t.screen.onkeypress(unpause)
# draw something
t.hideturtle()
t.pensize(5)
t.speed(1)
t.pu()
t.goto(-300,-300)
t.pd()
t.goto(-300, 300)
# pause until key is pressed
pause()
# draw some more
t.pu()
t.goto(300,-300)
t.pd()
t.goto(300, 300)
t.screen.mainloop()
The problem is that the sleep call loop totally blocks the keypress from being detected, even when I use a while loop of very short (100ms) sleeps.
If I hit a key while the first line is drawing, I see “unpause() called” in my console, so I know that the key binding is active.
Why doesn’t the keypress get detected? I don’t know about the internals, but I thought that the keystroke would be recorded in a buffer somewhere, and during the break between sleep calls, the listener would read the buffer and unset the paused
global variable. This is not happening.
Is there some other way I could implement this?
This is on a Debian Linux system.
3
Answers
Taking the ideas your suggestions have given me (thanks martineau and kederrac!) I was able to come up with a solution. It involves wrapping each of my drawing tasks in a function, then using a dispatch function that either waits for a keypress with an
ontimer
loop, or calls the next drawing function.This proof-of-concept code uses entirely too many globals, but it shows the technique:
Turtle graphics is based on
tkinter
, which is an event-driven GUI framework, so you can’t do things like you would in a regular procedurally-driven program — see @Bryan Oakley’s answer to the question Tkinter — executing functions over time for a more detailed explanation (although theturtle
module hides most of these details). Anyway, this fact means you shouldn’t calltime.sleep()
in an tight loop like that because everything has to happen without interfering with running of themainloop()
.The “trick” to avoid calling
time.sleep()
is to schedule periodic checks of the global variable using theturtle.ontimer()
function — so your program will work if the first part of it is changed as shown below:You Can Use turtle.done()
function.
Just make a input() function, and if input is entered, the program will run.
I tried this with basic approach.