As we saw before, it is possible to compose the interface for your application using multiple views; this holds true whether the view has an associated controller or not. I'm not going to provide an example embedding views and controllers because it's not very enlightening; it is easy to extend the original UI Composition example to use controller associated to the views, and that example is much more interesting if adapted to a ObjectList.
Since delegates inherit from views, it is also possible to compose a delegate with multiple child delegates (and even mix and match them with views). The requirement that the parent delegate be based on glade is the same, too: you should subclass GladeDelegate for your main window, though any kind of view can be attached to it.
The nice part about doing UI composition using delegates is that the interface and interaction is well encapsulated in a single class, and if you are careful when writing a child delegate, you can reuse that class in as many places of your applications as you like. I'm going to use the ObjectList from the last example to build a (rather fake) news browsing application in the next example:
#!/usr/bin/env python
import os
import gtk
from kiwi.ui import gadgets
from kiwi.ui.delegates import Delegate, SlaveDelegate
from kiwi.ui.objectlist import ObjectList, Column
class NewsItem:
def __init__(self, title, author, url):
self.title, self.author, self.url = title, author, url
# Friendly Pigdog.org news
news = [
NewsItem("Smallpox Vaccinations for EVERYONE", "JRoyale",
"http://www.pigdog.org/auto/Power_Corrupts/link/2700.html"),
NewsItem("Is that uranium in your pocket or are you just happy to see me?",
"Baron Earl",
"http://www.pigdog.org/auto/bad_people/link/2699.html"),
NewsItem("Cut 'n Paste", "Baron Earl",
"http://www.pigdog.org/auto/ArtFux/link/2690.html"),
NewsItem("A Slippery Exit", "Reverend CyberSatan",
"http://www.pigdog.org/auto/TheCorporateFuck/link/2683.html"),
NewsItem("Those Crazy Dutch Have Resurrected Elvis", "Miss Conduct",
"http://www.pigdog.org/auto/viva_la_musica/link/2678.html")
]
my_columns = [Column("title", sorted=True, tooltip="Title of article", width=50),
Column("author", tooltip="Author of article"),
Column("url", title="Address", visible=False,
tooltip="Address of article")]
class Shell(Delegate):
widgets = ["ok", "cancel", "header", "footer", "title"]
def __init__(self):
Delegate.__init__(self, gladefile="news_shell",
delete_handler=self.quit_if_last)
# paint header and footer; they are eventboxes that hold a
# label and buttonbox respectively
gadgets.set_background(self.header, "white")
gadgets.set_background(self.footer, "#A0A0A0")
gadgets.set_foreground(self.title, "blue")
# Create the delegate and set it up
objectlist = ObjectList(my_columns, news)
objectlist.connect('selection-changed', self.news_selected)
objectlist.connect('double-click', self.double_click)
slave = SlaveDelegate(toplevel=objectlist)
self.attach_slave("placeholder", slave)
slave.focus_toplevel() # Must be done after attach
self.slave = slave
def news_selected(self, the_list, item):
objectlist = self.slave.get_toplevel()
print "%s %s %s\n" % (item.title, item.author, item.url)
def double_click(self, the_list, selected_object):
self.emit('result', selected_object.url)
self.hide_and_quit()
def on_ok__clicked(self, *args):
objectlist = self.slave.get_toplevel()
item = objectlist.get_selected()
if item:
self.emit('result', item.url)
self.hide_and_quit()
def on_cancel__clicked(self, *args):
self.hide_and_quit()
url = None
shell = Shell()
shell.show_all()
def get_url(view, result):
global url
url = result
shell.connect('result', get_url)
gtk.main()
if url is not None:
# Try to run BROWSER (or lynx) on the URL returned
browser = os.environ.get("BROWSER", "lynx")
os.system("%s %s" % (browser, url))
Let's have a quick look at the code:
row_selected() for the select_row signal, which will be
called when a row is selected.
retval and
use it as input to run a browser for the selected news item (okay, so
the app is not really a browser, I lied).
This example shows a lot of the power of Kiwi; in a few lines, and with a little work in Glade, we have a working application that looks decent, behaves well and isn't hard to maintain. The next section will go on describing Proxies, which are high-level Views that represent an instance or part of it.