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.
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.
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.