Rapid Application Development with Python and Glade

Writing GUI programs involves two basic steps. First, you need to write
the code to create the interface, with elements, such as menus, and
widgets, such as buttons, labels and
entry fields. You then need to write the code that
executes when events occur, such as when a button is pressed or a menu
item is selected. When the program runs, it
enters an event loop that repeatedly waits for an
event and then calls the event handler, also known
as a callback function, that was defined for that
event. For example, you write a function to be called
when a button is pressed. Writing code to display
the widgets, defining the functions to be called
when events occur and connecting each event to the
specific function is a tedious process to do by hand.

For many widget sets, programs exist to lay out
the GUI visually. Damon Chaplin wrote the Glade program to
allow users to create an interface visually using the
GTK/GNOME widgets and also to specify which functions
to call when events occur. Glade stores the layout of
the widgets and the callbacks as an XML file. Glade
also generates a C or C++ program that contains
all the calls to create the widgets in the specified
layout, connect the callbacks and define empty
functions for each callback. However, Glade does
not create Python code. The GladeGen program I wrote
generates Python code based on the Glade XML file.

If you change your GUI using Glade, you need
Glade to output the new C/C++ code to create the
GUI. This can be annoying, especially if you have
modified the code that creates the GUI. James
Henstridge wrote libglade to alleviate the need
to hard code the GUI-generating code in your
program. James also started and helps maintain the
GTK/GNOME Python bindings, a Python module that
provides access to GTK/GNOME C functions. With
libglade, your program does not contain code to create
the interface. Instead, libglade parses the XML file
when your program is run and creates the interface on
the fly at runtime. Thus, whenever you change your
GUI using Glade, you do not need to change the code
that creates the interface.

I prefer using Python except in cases of code containing a lot of
computation where speed is crucial. Python's high-level data structures and interpretative environment
make it quick to develop, modify and maintain
code. The September 2003 issue of Linux Journal
contains an introductory article on PyGTK and Glade
(see the on-line Resources section) that readers
unfamiliar with Gtk and Glade will find helpful.

The motivation for GladeGen was a patient
database/accounting system I was writing for the
optometric/optical offices where my wife works. Before
my wife started working with them, they were using
a Microsoft Access database system someone
had written. That person had moved
out of state, and the office wanted a new system.
They talked to other optical offices
around town to find out what software was being
used. People at each office complained about the
software; the systems were buggy and expensive.
I convinced the owner of my wife's office that I could write a
custom system during the summer for about the same
cost as other new software, and that it would do exactly what they needed
it to do.
But, he had to let me use Linux.

The end result is a Python/GTK program that uses PostgreSQL as the
back-end database to store all of the data. This allows all of the searching
and tabulating to be done by SQL commands. The Python code provides
the layer of code that communicates between the PostgreSQL database
and GTK interface. Both GTK and PostgreSQL are written in C, so
they run fast. The Python code is more than fast enough on modern
processors for handling the communication between GTK and
PostgreSQL. The PyGTK front end and PostgreSQL database allow the client
front end to
access any database server so they can run the front-end GUI on multiple
computers and access the database server. The client/server setup allows them to run
the front-end GUI and access the PostgreSQL server at other
locations over the Internet through an SSH-encrypted connection. It
also allows me to have remote access from home when users have questions about
the system.

The program has more than 40 windows, including
those for entering patient information, frame/lens
purchases, contacts, reconciling insurance payments
and entering and tracking the frame inventory. I
decided to use Glade to create each window, and
because I wanted to use Python, I needed to write my
own software to automate code creation for each
window. The result is GladeGen.

GladeGen Usage

The code I have written automates the task of creating Python code to
create the interface, connect the callback functions,
provide access to the widgets and create empty callback functions
based on the Glade XML file. Using this software, the steps for
creating a GUI program are
1) use Glade to make the interface visually and save the XML file,
2) run GladeGen to generate the code
and 3) write the code for the callbacks.

The code
GladeGen creates contains all the code to run the application and
display your interface, along with empty callback functions. It also
allows you to use Glade to modify the interface. When you rerun
GladeGen, it regenerates the application code with any additional
callbacks and new widgets, without changing or modifying any of the
existing code.

Here, I demonstrate how to use GladeGen by creating a math quiz
program. The complete program is available from the Linux Journal FTP site (see Resources). GladeGen works with the GTK 2.x widget set and the
corresponding version of Glade, which on Red Hat systems is named
glade-2. If you are familiar with the GTK widgets, Glade is fairly
intuitive to use. If not, you should familiarize yourself with
the various container widgets, including table and horizontal/vertical box.

Using glade-2, I created the first version of the
interface. I started with a GtkWindow and added
a GtkVBox. I placed two GtkFrame widgets in the
vertical box and a GtkTable in each frame. All
the other widgets are placed in the two table
widgets. I used GtkSpinButton widgets to allow the
user to select the number of digits and operators
in the problem. GtkCheckButton widgets are used
to indicate which operators should be included in
the problem. GtkEntry widgets are used for the
problem, the answer and information on the number
of correct/incorrect problems answered. The other
widgets are GtkLabel and GtkButton widgets.

I saved the Glade file as mathflash.glade. Glade does not ask if
you want to save your file, so you need to remember to save it before
quitting if you make any changes to your interface. See Figure 1
for a
screenshot of the interface and Glade. It shows the reset_button
is configured to call the function on_reset_button_clicked when
the button is clicked.

Figure 1. Setting the Callback for a Button in Glade

Glade allows you to give each widget a name or provides a default
name. For the widgets we need to interact with, such as buttons
and data entry widgets, I provided names that match their intended
uses. With Glade, you also specify the signals you want to connect to
callback functions. As mentioned above, using Glade, I specified that
on_reset_button should be called when the reset_button is clicked.

Next, I used GladeGen to produce template code for
the application using the command GladeGen.py
mathflash.glade MathFlash MathFlash. The command-line
arguments are the name of the Glade XML file, the name
of the Python file/module to create and the name of
the class to create in that file/module. The resulting
MathFlash.py file can be found in Listing 1. The
MathFlash class subclasses a GladeWindow class, the
class that uses libglade to connect all the callbacks
listed in the handlers variable. It also creates a
dictionary, self.widgets, that maps each widget name
in the widget_list variable to the corresponding
GtkWidget instance. The GladeWindow subclass provides
default show and hide methods so that the template
code can be run immediately to view the interface before
you start writing the callbacks.

Comment viewing options

In www.oneminutepython.com I show you how to develop an application in only one minute! It contains direct links to key (all open source) applications (python, wxpython etc.) and a template application.

I am pulling my hair off for almost 4 hours as to why my gtk window is not appearing... it was because I did not write the window.show() statement. No blog/article I have found until now include that line. I even reinstalled my glade and python thinking the error was with them.

Each toplevel widget in a glade file can be associated with a GWidget
class. Methods of that class if has prefix `on_`, are treated as
signal handlers for widgets under the tree of toplevel widget in
glade file. Signal handlers are of the form::
on_widgetname__signalname

``signalname`` if contains hyphens should be replaced with
underscores. If signal handler method name additionally ends with
double underscore (__), then ``connect_after`` is used to connect
that method.

``on_quit`` method if defined will be connected to ``delete-event``
event of the toplevel widget.

Any widget in the glade file (comming under toplevel widget) can be
accessed as if there is an instance variable named by that widget name.
Toplevel widget is always accessible through the ``widget`` instance
variable.

:CVariables:
- `GLADE_FILE`: Path of the glade file to use.
- `TOPLEVEL_NAME`: Name of the toplevel widget.
"""