The UI Delegate classes, located in the kiwi.ui.delegates module, use multiple inheritance, being derived from both a View and a Controller. This means they combine functionality from both into a single class: not only does it specify the interface, it also handles the widget signals. It's the "can't beat them, join them" solution to the V+C coupling problem, and it's used in Swing, MFC and Bakery, a C++ framework for GTK+.
The Delegate class is a combination of BaseView and BaseController. You can use it to create your interface programatically and then hook up handlers to it, just like you would do to individual views and controllers. A very simple (yes, I too get bored of hand-coding PyGTK widgets) example follows, found in the distribution as examples/framework/simple.py:
#!/usr/bin/env python import gtk from kiwi.ui.delegates import Delegate class Hello(Delegate): def __init__(self): self.index = 0 self.text = ["I've decided to take my work back underground", "To keep it from falling into the wrong hands."] topwidget = gtk.Window() topwidget.set_title("So...") self.button = gtk.Button(self.text[self.index]) self.button.show() topwidget.add(self.button) Delegate.__init__(self, topwidget, delete_handler=gtk.main_quit) # focus button, our only widget self.focus_topmost() def on_button__clicked(self, button): self.index = self.index + 1 # Two clicks and we're gone if self.index > 1: self.hide_and_quit() # the *handler's* return value disappears into GTK+ return # update the label of the button button.set_label(self.text[self.index]) app = Hello() app.show_and_loop()
As you can see, the Delegate was the only class we needed to inherit from and instantiate. This makes the amount of infrastructure code go down significantly, and most single-window applications (and individual dialogs in multi-window applications) can be implemented with single Delegate and GladeDelegate subclasses. As an example for using the GladeDelegate, below is a third version of our temperature conversion application, examples/Faren/faren3.py:
#!/usr/bin/env python import gtk from kiwi.ui.delegates import Delegate class Farenheit(Delegate): widgets = ["quitbutton", "temperature", "celsius", "farenheit", "celsius_label" , "farenheit_label", "temperature_label"] gladefile = "faren" def __init__(self): Delegate.__init__(self, delete_handler=self.quit_if_last) def convert_temperature(self, temp): farenheit = (temp * 9/5.0) + 32 celsius = (temp - 32) * 5/9.0 return farenheit, celsius def clear_temperature(self): self.farenheit.set_text("") self.celsius.set_text("") # Signal handlers def on_quitbutton__clicked(self, *args): self.hide_and_quit() def after_temperature__changed(self, entry, *args): temp = entry.get_text().strip() or None if temp is None: self.clear_temperature() else: try: farenheit, celsius = self.convert_temperature(float(temp)) except ValueError: farenheit = celsius = float('nan') self.farenheit.set_text("%.2f" % farenheit) self.celsius.set_text("%.2f" % celsius) delegate = Farenheit() delegate.show() gtk.main()
As you can see, using the delegates makes a lot of sense in many cases: the view and controller split isn't essential, and you can end up with a lot less code with the same functionality at no reduced maintainability or readability, which is what we are aiming for. For larger applications, or apps where a lot of very unusual functionality is required, it may still make sense to use separate Controllers and Views, but for normal development, stick to delegates; they simplify things.
Note that there is also a SlaveDelegate, which works like a normal SlaveView with an attached Controller.