Building GUI Applications with PythonCard

Author: Andrew J Todd
Date: October, 2005

Introduction

As the subject of my presentation at the Open Source Developers Conference 2005 is an interactive demonstration this conference paper is provided as background reading for those requiring more information. A version is posted to my web site [1] along with the slides that accompanied this presentation [2].

Overview

PythonCard is a simple, cross platform, graphical user interface application construction kit. The PythonCard motto is "Simple things should be simple and complex things should be possible."

Its major features are a framework that sits on top of wxPython [3] packaged with comprehensive documentation, some impressive runtime tools and a wide variety of sample applications.

PythonCard is aimed at people who are new to programming GUI applications. It is designed to offer a shallow learning curve and is ideally suited to the kind of small scale developments that people new to programming wish to develop, the kind of applications that "scratch an itch". It is most useful for simple applications that can be built in a day or so. Usually by a single developer. It can, and has, been used to build more complex applications involving the efforts of small teams but it isn't an enterprise tool. If this were a marketing presentation we would be saying that the competition is tools like Visual Basic for Applications, where you can build powerful stand alone applications quite quickly and easily but that don't necessarily scale to large user populations or teams numbering more than a handful of developers. By that stage we recommend you move up to the more complex and enterprise ready wxPython.

PythonCard is not HyperCard, nor is it a Visual Basic clone, although the aim of the project is to provide a toolkit with similar facilities and tools.

PythonCard also has the benefit of being cross platform, working on Windows, Macintosh OS X and Linux (Gtk). Applications developed on one operating system will work (and can be further developed) on any of the others.

PythonCard is 100% Python. We consider this to be a good thing. For instance, it means the source code of the framework and tools are easily available to all. This, in turn, means that they can act as style and implementation guides to people who want to take their applications that little bit further.

PythonCard is a framework on top of wxPython and follows the published API standards (primarily that method names are mixedCamelCase). Where possible the name for something in PythonCard is the same as the underlying wxPython component. This has the added benefit of easing the transition from PythonCard to wxPython should it be needed in your application. PythonCard aims to hide the complexity of wxPython without suppressing any of its features.

Probably the most compelling feature of PythonCard is its separation of presentation and application logic. The presentation features of your application are defined in resource files (which are just dictionaries actually) and the application logic is in a separate Python file. Removing the necessity for lots of code to describe your application's windows, widgets and associated control items means that the application module is usually quite short. It also means that the developer can concentrate on their application logic. PythonCard takes care of everything else.

This separation is supported by the automatic binding of events to components. As long as you follow the naming conventions for code objects (usually methods of your application class) they will automatically be associated with widgets in your application at runtime and executed at the appropriate point. In fact its so good that Microsoft is adopting this approach in the upcoming Avalon toolkit with the use of XAML files to define layout. This standardised naming convention also helps the generation of boilerplate code. We expect to leverage this in future versions of the development tools much like the facilities available in tools like Visual Basic where the user can select an application component and jump from it to the code editor with the method stub created for them.

PythonCard is an open source project and is being developed under the terms of a BSD-style license. This basically means you are free to download and use the executables, source code, web pages or any other item produced by the project and use it as you wish, as long as you acknowledge the source of that item and replicate the license associated with it.

History

The PythonCard project started in June 2001. It came about as a direct result of a thread [4] on the comp.lang.python news group. It transpired that many Python programmers were looking for a simple and easy way to build graphical user interfaces for their existing programs and were frustrated with the existing frameworks and toolkits. There was also a fairly common appreciation for HyperCard, the genre defining application development toolkit that ran on the Apple Macintosh. Long since abandoned by Apple it was seen as the ideal example of a simple, intuitive but powerful way of developing graphical applications. The thread was so popular that a seperate discussion list was started at Yahoo! Groups [5].

After reviewing the available GUI toolkits (Tkinter, Qt and wxPython) the list members decided against the one size fits all approach (and the anygui project was started as a result of that discussion) and decided to build PythonCard using the wxPython framework. The initial model for PythonCard was HyperCard, although it was always more of an inspiration than a blueprint. You will find some HyperCard terms in PythonCard to this day, in particular the idea of a "background" which started life as a version of HyperCard's card.

After an initial burst of discussion a prototype framework was developed (mainly by Kevin Altis and Rowland Smith) and it was agreed to move the project to SourceForge. Unfortunately someone had already registered a project called PythonCard and there was some discussion of alternative names for the project. Luckily the existing PythonCard project was defunct and after an appeal to the original project owner the current project took over the SourceForge project [6].

The first release of PythonCard took place in July 2001 and the latest (0.8.1) on the 19th of October, 2004. Since that date work has been progressing towards the totemic 1.0 release with most of the development effort directed towards bug fixing, cleaning up the code and fitting in the final few features deemed necessary for such an auspicious milestone. At the moment we can say that the 1.0 release is close but making predictions of its release date would be premature. As with all of the best open source projects it will be released when its ready.

There have been a number of milestones during the four years of the project. The framework developed quite quickly and has been in the main unchanged for the majority of the project's life. Each release has brought a more robust and featureful framework as well as more tools (both runtime and developer focussed) and more and more sample applications. Which is just a way to say that although its only at release 0.8.1 PythonCard is a mature and stable project suitable for developing production quality applications.

The Framework

PythonCard has evolved over the last four years into more than just a framework. There is a suite of documentation, accompanying tools to aid development (the resourceEditor, codeEditor and textEditor) some fantastic debugging tools (pycrust, message watcher and interactive property editor) and many sample applications (65 at the last count) showcasing tips, techniques and practical tools all built using PythonCard.

The primary ways that PythonCard simplifies the GUI development process are that it standardises event and attribute names, automatically binds event handlers (where present) to your components and separates program logic from application presentation. Each of these may seem like a restriction but allows the developer to focus on the important parts of their applications - the layout of the graphical interface and the application logic - without having to master a complex windowing toolkit. The separation of the presentation (in a resource file) and the application logic (in a Python module) in particular provide a much simpler application structure for the developer. And simplicity is what PythonCard is all about.

Having the presentation aspects of the application in their own file enables the use of tools like the resourceEditor. The new user of PythonCard doesn't need to know anything about the format of the resource file, they can use a graphical tool to layout their application and it will generate the resource file for them. Of course this doesn't mean that you have to use the resourceEditor, the resource file is a text file containing a Python dictionary and can just as well be written in the text editor of your choice.

The basic building blocks of the framework are the components (currently numbering 29) that are available for immediate use in your application. These allow you to easily add functionality to your PythonCard application by simply placing an item in your resource file. Need to have a date entry field? Use the calendar component? A sliding scale? Use the slider. A tree control? Use the tree component. You don't need to use any wxPython code because PythonCard takes care of initialisation, event binding, styles, etc. Some of these components are made up of several wxPython widgets joined together with suitable event support saving the application developer from writing a lot of scaffolding code in their application which has nothing to do with their actual application subject area.

Resource Files

PythonCard's resource files are essentially just Python dictionaries. Here's an example from the minimal sample application;

    { 'application': 
        { 'type':'Application',
          'name':'Minimal', 
          'backgrounds': 
            [ { 'type':'Background',
                'name':'bgMin',
                'title':'Minimal PythonCard Application',
                'size':( 200, 100 ),
                'menubar': 
                  { 'type':'MenuBar',
                    'menus': [
                              { 'type':'Menu',
                                'name':'menuFile',
                                'label':'&File',
                                'items': [ 
                                          { 'type':'MenuItem',
                                            'name':'menuFileExit',
                                            'label':'E&xit\tAlt+X',
                                            'command':'exit' } ] }
                             ]
                  },
                'components':
                  [ 
                    { 'type':'TextField',
                      'name':'field1',
                      'position':(5, 5),
                      'size':(150, -1),
                      'text':'Hello PythonCard' },
                  ]
              } ]
        }
    }
    

As you can see it's not very complex, and more readable than an XML equivalent. Having said that though, there's no reason why PythonCard couldn't use an XML form for its resource files, perhaps even supporting wxPython's xrc file format [7]. The real beauty of the resource file format though is that it can simply be read and evaluated in place without requiring any processing because it's just Python.

To briefly explain, a resource file has a dictionary containing the definition of the application. This contains one or more backgrounds each of which can have an associated menu bar (made up of menus which have one or more items) and a collection of components. Each component is defined by its own dictionary, which should specify amongst other things the PythonCard component [8] that it implements. In these dictionaries you can specify values for the component's properties.

Even though it's quite a simple format the aim of PythonCard is to make the simple things simple and that's why we have the resource editor which is discussed in the tools section below.

Despite this talk of the benefits of the resource file approach it should be noted that your application doesn't need a resource file. You can define your own resource dictionary and pass it to the application initialisation routine. The noresource sample demonstrates how to do this.

Components

At their simplest PythonCard's components are just a simple wrapper around the underlying wxPython control, e.g. the Button [9] and StaticText [10] components, and at their most complex, e.g. the codeeditor, are practically mini applications in their own right.

The component's public interface are a number of attributes and events. The event names are important because they determine the name of the methods that are automatically bound to your components from your application code. If you want to know which events are available for each component they are documented on the project web site [11] and in the documentation packaged with the PythonCard framework.

Application Code

The most striking feature of a PythonCard application is the code you don't have to write. In a normal application with a graphical interface you have to write code to do the following things;

  1. Initialise your application
  2. Create the windows your are going to use
  3. Place drawing areas (frames) within these windows
  4. Create widgets which exist within these frames
  5. Create your menus and their items
  6. Register the events that your application is going to respond to
  7. Write the code that will be executed when these events occur

With PythonCard you can just concentrate on the last item, although you do need a couple of lines to do the first as well. This in turn means that you can have a working application much faster than if you code it all from scratch. Here's the application module from the minimal sample;

    #!/usr/bin/python
    """
    __version__ = "$Revision: 1.10 $"
    __date__ = "$Date: 2004/04/24 22:13:31 $"
    """

    from PythonCard import model
    
    class Minimal(model.Background):
        pass
    
    if __name__ == '__main__':
        app = model.Application(Minimal)
        app.MainLoop()
    

Pretty short isn't it? But then again this sample application doesn't do much. As you can see from this combination of the application code and the resource file we showed earlier it is possible to have a working PythonCard application just by assembling one or more components on a background within your application.

The primary component in the application code is your application class which must inherit from model.Background. This is then initialised in the last two lines of the script to start the application running.

The application class is the place where we put our event handlers. In the simplest case you will just add a single method for each event you wish to handle. Most of these event methods will be defined for a specific widget but you can choose to bind them to your background instead. The method name is very important as it determines when that block of code is executed. The form of method names is on_(component_name)_(event name) or for application wide methods on_(event name).

So, for example, in our minimal sample we could have a method called on_field1_gainFocus. The code in this method would then be executed whenever the text field called field1 became the focus of the application (usually by clicking on it). A more specific event handler will always trump a less specific one. So if you specify an event handler on the background and another on a specific widget the background one will fire unless the focus of the running application is in the widget in which case its own event handler will be executed.

The added bonus of PythonCard is that whenever you need to go beyond the features provided by the framework you can use native wxPython code. Nothing is hidden from the developer but the simplicity and convenience of the PythonCard framework remove the need for a lot of boilerplate code so that the developer can concentrate on their application and not having to wrangle a GUI toolkit.

Tools

PythonCard comes with two sets of tools. The first are tools to help you build your PythonCard application and the second enable you to understand exactly what's happening when you run it.

The development tools between them cover all of the features you'd expect to see in an integrated development environment (IDE), just lacking the integrated part at the moment. The resourceEditor allows the developer to layout their backgrounds and associated widgets graphically and handles reading and writing files in PythonCard's resource file format thus removing the need to learn what can be a complicated format to the beginner. The codeEditor (which is a specialised version of the textEditor tool) provides a fully featured programmer's editor complete with Python support and the ability to syntax check and run your code from within the editor. findFiles, the last of our development tools provides a means of searching through files for specific names or contents. Ideal for rediscovering that snippet of code you wrote that will be perfect in the file you are currently editing.

The runtime tools are another of PythonCard's jewels. The Logger builds on Python's logging library module to enable different levels of messages to be produced from your PythonCard application. The logger provides the infrastructure to manage log output leaving the developer to simply use the convenience methods it provides.

The Message Watcher integrates with the wxPython event model to show you in real time the events that are being triggered when a PythonCard application is running. It helps determine where the application code should go and verify that a PythonCard application is operating as expected.

The property editor, which is also used in the resourceEditor tool, allows for the inspection and updating of application component properties. These changes then appear in the running application as soon as the update button is pressed. This is a marvelous example of the power of dynamic languages and a great aid to prototyping.

In tandem with the property editor we have the namespace viewer which provides a graphical view of the structure of a running PythonCard application. A tree view shows the hierarchy of application, backgrounds and widgets along with their associated properties and methods.

PythonCard has come with the PyCrust shell since it was first written. This allows even more control of the running application, including the ability to interact with application objects. The shell can be used to execute small snippets of Python code within the context of the running application. When used during development it's a great way to try out trigger code before putting it into the application code.

Samples

PythonCard currently ships with sixty five (yes 65) sample applications, from the simplistic minimal sample I showed in previous sections to a soduku solver, an mp3 player and a fully featured webserver.

All of the applications use the features of wxPython through PythonCard but they then also introduce a lot of other Python modules. There are sample applications that connect to databases, draw bit mapped pictures and provide network services using Twisted and SOAP.

Adding to that are the development tools I've already mentioned that are all themselves built using PythonCard. For a demonstration of the sample applications PythonCard comes with a sample application launcher (built in PythonCard naturally) that you will find in the top level samples directory after you've installed the framework. This not only allows you to view the available samples and their associated descriptions but also allows you to launch them with the runtime tools mentioned above.

Future Plans

The next release of PythonCard is going to be the 1.0. There will only be very minor (or no) framework changes between now and 1.0. We were waiting for the release of wxPython 2.6 and the only step that's left before the 1.0 version is released is some serious testing. The project documentation also needs updating so any offers of assistance will be gratefully received.

References