A few weeks ago I starded interresting about Twisted and asynchronous programming. I realy liked the way that Twisted handles events and callbacks.
I’ve been working in a program with a graphical interface built in PyGTK that uses threads for every single taks and I wondered if I can had this program running in just one thread asynchronously. It’s realy simple implement twisted code in a PyGTK applicacion since both are event-based and Twisted has a native API to do so.
Let’s build a simple PyGTK example:
import gtk class Gui: def __init__(self): self.window = gtk.Window() self.window.set_default_size(200,200) self.window.set_title("Simple PyGTK program") self.vbox = gtk.VBox() self.button = gtk.Button("I'm a button!") self.label = gtk.Label("Nothing here") self.vbox.pack_start(self.button) self.vbox.pack_start(self.label) self.window.add(self.vbox) self.button.connect("clicked", self.on_clicked) self.window.connect("destroy", lambda x: gtk.main_quit()) self.window.show_all() self.window.show() def on_clicked(self, widget): self.label.set_text("You clicked the button!") if __name__ == "__main__": app = Gui() #starts the GTK loop gtk.main() |
So, this example is using the Gtk loop. Twisted applications use the Twisted reactor, and we need the Twisted reactor to “understend” Gtk signals.
This is what you have to do:
from twisted.internet import gtk2reactor # for gtk-2.0 gtk2reactor.install() #Your code #... from twisted.internet import reactor #this starts the reactor reactor.run() |
Now we can re-implement our first example and it would look like this:
import gtk from twisted.internet import gtk2reactor # for gtk-2.0 gtk2reactor.install() #this installs the gtk reactor #NOTE: This have to be at top always, before importing the reactor class Gui: def __init__(self): self.window = gtk.Window() self.window.set_default_size(200,200) self.window.set_title("Simple PyGTK program") self.vbox = gtk.VBox() self.button = gtk.Button("I'm a button!") self.label = gtk.Label("Nothing here") self.vbox.pack_start(self.button) self.vbox.pack_start(self.label) self.window.add(self.vbox) self.button.connect("clicked", self.on_clicked) self.window.connect("destroy", lambda x: gtk.main_quit()) self.window.show_all() self.window.show() def on_clicked(self, widget): self.label.set_text("You clicked the button!") if __name__ == "__main__": app = Gui() #No Gtk anymore! #gtk.main() from twisted.internet import reactor #let's start the loop reactor.run() |
Now you can enjoy the Twisted power in your graphical apps, here is a (very)simple example using Twisted-way callbacks.
import gtk import time from twisted.internet import gtk2reactor # for gtk-2.0 gtk2reactor.install() #this installs the gtk reactor #NOTE: This have to be at top always, before starting the reactor class Gui: def __init__(self): self.window = gtk.Window() self.window.set_default_size(200,200) self.window.set_title("Simple PyGTK program") self.vbox = gtk.VBox() self.button = gtk.Button("I'm a button!") self.time = time.time() self.label = gtk.Label("0") self.vbox.pack_start(self.button) self.vbox.pack_start(self.label) self.window.add(self.vbox) self.button.connect("clicked", self.on_clicked) self.window.connect("destroy", lambda x: gtk.main_quit()) self.window.show_all() self.window.show() self.time = time.time() def on_clicked(self, widget=None): self.label_text = time.time() - self.time self.label.set_text("%.2fs" % self.label_text) #Twisted will call the sefl.on_clicked function every 100ms reactor.callLater(.1, self.on_clicked) if __name__ == "__main__": app = Gui() #No Gtk anymore! #gtk.main() from twisted.internet import reactor #let's start the loop reactor.run() |
Twisted also has APIS for others toolkits such as Tkinter, wxPython, Win32(Windows) and PyUI.
For more information you can visit the official documentation.