{"id":367,"date":"2012-11-10T02:30:20","date_gmt":"2012-11-10T07:30:20","guid":{"rendered":"http:\/\/www.virtualroadside.com\/blog\/?p=367"},"modified":"2012-11-10T02:44:20","modified_gmt":"2012-11-10T07:44:20","slug":"glib-idle_add-for-tkinter-in-python","status":"publish","type":"post","link":"http:\/\/www.virtualroadside.com\/blog\/index.php\/2012\/11\/10\/glib-idle_add-for-tkinter-in-python\/","title":{"rendered":"glib.idle_add for tkinter in python"},"content":{"rendered":"<p>After doing a lot of python GTK+ work on Exaile, I&#8217;ve found that it uses glib.idle_add() extensively &#8212; and usually with good reason. idle_add is great if you want to ensure that whatever you&#8217;re calling is being called on the GUI thread, so that way you don&#8217;t have to worry too much about thread interactions as long as you keep things separate.<\/p>\n<p>Another mentor and I are developing a GUI video game along with a &#8216;fake wpilib&#8217; for our FIRST Robotics programming students to help them learn how to program, and as such we&#8217;ve decided to use TKinter for the GUI toolkit (since it supports Python 3, and usually doesn&#8217;t require the kids to install anything special to make it work). However, as I started making things I couldn&#8217;t find the equivalent of idle_add() for TKinter, and I guess there isn&#8217;t one &#8212; after_idle() apparently blocks until the event loop is idle, and so that isn&#8217;t what I wanted.<\/p>\n<p>A number of posts I found online advocated to poll a queue for input&#8230; 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.<\/p>\n<pre>    \u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 \r\nimport Tkinter as tk\r\nfrom queue import Queue, Empty\r\n\r\ndef idle_add(callable, *args):\r\n\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 '''Call this with a function and optional arguments, and that function\r\n\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 will be called on the GUI thread via an event.\r\n\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 \u00c2\u00a0\r\n\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 This function returns immediately.\r\n\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 '''\r\n\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 queue.put((callable, args))\r\n\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 root.event_generate('&lt;&lt;Idle&gt;&gt;', when='tail')\r\n\u00c2\u00a0\u00c2\u00a0 \u00c2\u00a0\r\ndef _on_idle(event):\r\n\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 '''This should never be called directly, it is called via an \r\n\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 event, and should always be on the GUI thread\r\n\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 '''\r\n    while True:\r\n        try:\r\n            callable, args = queue.get(block=False)\r\n        except queue.Empty:\r\n            break\r\n        callable(*args)\r\n\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0\u00c2\u00a0 \u00c2\u00a0\r\nqueue = Queue()\r\nroot = tk.Tk()\r\nroot.bind('&lt;&lt;Idle&gt;&gt;', _on_idle)<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>After doing a lot of python GTK+ work on Exaile, I&#8217;ve found that it uses glib.idle_add() extensively &#8212; and usually with good reason. idle_add is great if you want to ensure that whatever you&#8217;re calling is being called on the GUI thread, so that way you don&#8217;t have to worry too much about thread interactions [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"_links":{"self":[{"href":"http:\/\/www.virtualroadside.com\/blog\/index.php\/wp-json\/wp\/v2\/posts\/367"}],"collection":[{"href":"http:\/\/www.virtualroadside.com\/blog\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.virtualroadside.com\/blog\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.virtualroadside.com\/blog\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.virtualroadside.com\/blog\/index.php\/wp-json\/wp\/v2\/comments?post=367"}],"version-history":[{"count":8,"href":"http:\/\/www.virtualroadside.com\/blog\/index.php\/wp-json\/wp\/v2\/posts\/367\/revisions"}],"predecessor-version":[{"id":374,"href":"http:\/\/www.virtualroadside.com\/blog\/index.php\/wp-json\/wp\/v2\/posts\/367\/revisions\/374"}],"wp:attachment":[{"href":"http:\/\/www.virtualroadside.com\/blog\/index.php\/wp-json\/wp\/v2\/media?parent=367"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.virtualroadside.com\/blog\/index.php\/wp-json\/wp\/v2\/categories?post=367"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.virtualroadside.com\/blog\/index.php\/wp-json\/wp\/v2\/tags?post=367"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}