glib.idle_add for tkinter in python

After doing a lot of python GTK+ work on Exaile, I’ve found that it uses glib.idle_add() extensively — and usually with good reason. idle_add is great if you want to ensure that whatever you’re calling is being called on the GUI thread, so that way you don’t have to worry too much about thread interactions as long as you keep things separate.

Another mentor and I are developing a GUI video game along with a ‘fake wpilib’ for our FIRST Robotics programming students to help them learn how to program, and as such we’ve decided to use TKinter for the GUI toolkit (since it supports Python 3, and usually doesn’t require the kids to install anything special to make it work). However, as I started making things I couldn’t find the equivalent of idle_add() for TKinter, and I guess there isn’t one — after_idle() apparently blocks until the event loop is idle, and so that isn’t what I wanted.

A number of posts I found online advocated to poll a queue for input… but I *really* dislike polling, and try to avoid it when I can. So I wrote up this set of routines that is roughly equivalent to idle_add() in tkinter, and uses a queue while avoiding polling.

import Tkinter as tk
from queue import Queue, Empty
def idle_add(callable, *args):
'''Call this with a function and optional arguments, and that function
will be called on the GUI thread via an event.
This function returns immediately.
'''
queue.put((callable, args))
root.event_generate('<<Idle>>', when='tail')
def _on_idle(event):
'''This should never be called directly, it is called via an
event, and should always be on the GUI thread
'''
while True:
try:
callable, args = queue.get(block=False)
except queue.Empty:
break
callable(*args)
queue = Queue()
root = tk.Tk()
root.bind('<<Idle>>', _on_idle)

This entry was posted
on Saturday, November 10th, 2012 at 2:30 am and is filed under General.
You can follow any responses to this entry through the RSS 2.0 feed.
You can skip to the end and leave a response. Pinging is currently not allowed.