Once you have written three (two?) applications using the PyGTK classes and commands directly, you get very bored of hand-coding the widgets and their structure. Sure, you have total control over them, and you can build them programatically, which is why you might want to do it for small parts of your application, but for anything that is medium to large-scale, having to maintain all that code makes changing the UI very painful. Damon Chaplin's application Glade provides a way to create a GTK+ interface visually, and it is normally used to generate C or C++ code that creates the widgets. It also saves the interface specification in an XML file. Knowing this, James Henstridge, the author of PyGTK, wrote libglade, a killer library (this was years ago, but I digress) that renders widgets based on specifications in an XML file. libglade allows you to keep the interface definition separate from the code, which is an awesome idea, since it drastically reduces the amount of interface code (and the consequent burden of maintaining it). Being able to use Glade to revisit and tweak your interface without having to regenerate code is also a huge advantage.
Anyway, Kiwi lets you use Glade interfaces in a very convenient
manner, by using the BaseView class. Let's show this off by
redoing the last example using glade. First thing would be running Glade
and creating a window and putting a label into it. Name the window
hey
and turn the visible property off (using the Common tab of
the Properties dialog). Save the file (careful with that Save dialog, it
creates directories and is generally evil in my opinion) as
hey.glade. And then code up heyglade.py
(all this is
available in examples/framework/hey/heyglade.py):
#!/usr/bin/env python import gtk from kiwi.ui.gadgets import quit_if_last from kiwi.ui.views import BaseView app = BaseView(gladefile="hey", delete_handler=quit_if_last) app.show() gtk.main()
Oops. Where did all that code go? Right, we are now using the glade file
to generate the UI. So we didn't even need to subclass
BaseView; we just passed in a parameter that told it what glade
file to use, and the same delete handler. Note also that we used
show_and_loop()
instead of
show_all_and_loop()
3.
The gladefile
parameter indicates the file it should open. If the
name you pass in doesn't have a .glade suffix, BaseView
will append it and try to open it; in our cases, it will try to open the
file hey.glade. However, this argument does a bit more than just
specifying the file (when using this form of the constructor, which is
simplified): it also specifies by default the name of the toplevel
widget in the glade file. This is why I specifically stated the window
should be named hey
two paragraphs back. That widget is attached
to the view instance with the name toplevel
.
If you want to use another specific toplevel widget name, just use the
extra constructor parameter toplevel_name
. This can be useful
if you have many windows in the same Glade file; you can reuse the glade
file by just defining multiple BaseView
instances (or subclass
instances) with the same gladefile
but specifying different
toplevel widgets as each individual toplevel_name
.
There are some common mistakes to be made when using the BaseView, and Kiwi raises special exceptions for three them.
Kiwi.Views.set_gladepath()
), and if it doesn't find it, it will
complain with an IOError and stop.
toplevel_name
, of course. Kiwi raises an
AttributeError here.
To use BaseView effectively, it's important to define the
widgets
list, which defines what widgets are to be attached to
your class. This list has its own semantics, which I discuss in the next
section.
show_all_and_loop()
--
you must use show_and_loop()
instead. There is a reason for
this. show_all means that all widgets under the toplevel widget should
be shown; however in glade, since most widgets are visible by default,
you only need to turn off visibility on the toplevel window to get the
default hidden effect. This alone would not be a problem, but the fact
is that certain widgets can be configured in glade to *require* being
hidden (either because you want them initially hidden, or because they
do something special, like the gtk.Toolbar: if you choose to use `Only
Text' or `Only Icons', glade implements this by hiding the icons or
text, respectively). This would break with show_all and too many bug
reports told me it was enough reason to turn it off. You can of course
call it manually on the window if you are really determined do so.