Using generators to sleep without blocking
February 12, 2002 | Fredrik Lundh
The following Tkinter snippet draws a random polyline, one segment at a time.
The main work is done inside the draw method, which uses yield x to sleep for x milliseconds. The yield statement transfers control to the slowmotion wrapper, which tells Tkinter to process events as usual, and call back after the given time. When Tkinter calls the scheduled function, we end up in draw, just after the yield statement. The function draws another line, and goes back to sleep.
from __future__ import generators # only needed in 2.2 import random from Tkinter import * w, h = 500, 500 root = Tk() cnv = Canvas(root, width=w, height=h) cnv.pack(side=TOP) Button(root, text='Enough', command=root.quit).pack(side=TOP) def draw(): x, y = random.randrange(w), random.randrange(h) while 1: oldx, oldy = x, y x, y = random.randrange(w), random.randrange(h) cnv.create_line(oldx, oldy, x, y) yield 500 # sleep for 500 ms def slowmotion(iterator): # sleep a while, and then go back to the loop root.after(iterator.next(), slowmotion, iterator) slowmotion(draw()) # schedule the first round mainloop() # get things going
The important thing here is that the event loop keeps running. Most of the time is spent inside the Tkinter event loop, waiting to call the slowmotion helper again. Other widgets can process their events as usual, and you can click the “Enough” button at any time.