September 8, 2008

Dress up your Python scripts with EasyGui

Author: Dmitri Popov

In many cases, adding a graphical interface to Python scripts means getting your hands dirty with TKinter or other GUI programming kits. This exercise is usually reserved for users who have already acquired decent Python programming skills, as it requires some serious code wizardry. Thankfully, the EasyGui module allows you to add some GUI goodness to your Python scripts without going through coding rigmarole. Using EasyGui, you can add visual elements with just a few lines of code.

The best way to discover EasyGui's capabilities is to use it to improve an existing Python script. I put it to work on Pygmynote, a simple data managing tool I created for my personal use to keep tabs on my notes, URLs, and to-dos. Although Pygmynote is not all that difficult to use, adding a few input boxes and dialogs would make it even easier to enter and retrieve records.

Before you start tweaking a script, you have to install EasyGui. Download the latest release of the module, unpack the downloaded archive, and move the file into the /usr/lib/python2.5/site-packages directory. To import the module into your script, add the from easygui import * line in the beginning of the script. Now you are ready to tweak the script.

Let's start from the beginning and replace the simple "Pygmynote is ready. Pile up!" greeting message with a fancy message box. The msgbox function takes at least one parameter, the message to display:

msgbox("Pygmynote is ready.")

There are three other parameters you can specify for the message function: the box title, the button label (by default, it's "OK"), and the image. You can use the latter parameter to spice up the message box by adding a .gif image to it. Here is an example of the msgbox function with all the available parameters:

image = "pygmynote.gif"
msgbox("Pygmynote is ready.", "Pygmynote", ok_button="Pile up!", image=image)

To make it easier for users to keep tabs on Pygmynote's commands, you can add a menu containing a list of the available commands. The user can then execute the desired command by selecting it from the list and pressing OK, or by simply double-clicking on the command. To do this, you can use EasyGui's choicebox function. Similar to the msgbox, the choicebox takes three parameters: the choicebox's message, the window title, and a list of options:

msg ="What's your favorite fruit?"
title = "Fruity"
choices = ["Apple", "Apricot", "Pineapple"]
choice = choicebox(msg, title, choices)

When the user chooses one of the list items and presses OK (or double-clicks on the item), the function returns the name of the item. To make the choicebox work with Pygmynote, you have to specify the script's commands as list entries:

msg ="Select command and press OK"
title = "Pygmynote"
choices = ["Help", "Insert new record", "Show all records", "Quit"]
command = choicebox(msg, title, choices)

You should also replace the command names in the conditional blocks so they match the items in the choicebox, so command=="n" becomes command=="Insert new record". If you now run the script, you'll notice that the entries in the box are sorted alphabetically. But what if you want the "Insert new record" entry to be the first on the list, or order all the items the way you want? While EasyGui doesn't allow custom sorting, you can use a simple workaround: place numbers or letters to force a custom order, for example, "1 - Insert new record" or "X - Quit".

Next stop is the part of the Pygmyscript that shows a list of found records. The following code block displays all existing records:

elif command=="a":
cursor.execute ("SELECT * FROM notes ORDER BY id ASC")
rows = cursor.fetchall ()
for row in rows:
print "\n %s %s [%s]" % (row[0], row[1], row[2])
print "\n Number of records: %d" % cursor.rowcount

Using the textbox function you can make the script display the found records in a nice text box. To do this, you have to tweak the code block so it turns the list of found records into a string. Use the result_list = [] statement to create an empty list and use the .append method to add records to it. You can then use the generated list as a parameter of the textbox function:

elif command=="Show all records":
cursor.execute ("SELECT * FROM notes ORDER BY id ASC")
rows = cursor.fetchall ()
result_list = []
for row in rows:
record_str = "\n%s %s [%s]" % (row[0], row[1], row[2])
result_list.append (record_str)
textbox ("Found records:", "Pygmynote", result_list)

EasyGui's boolbox function can come in handy for controlling the flow of the script. For example, when you update a record in Pygmynote, the script asks whether you want to update the record's note or tags. The script then updates the appropriate field in the record. The original code block that does all that is as follows:

elif command=="u":
input_id=raw_input("Record id: ")
input_type=raw_input("Update note (n) or tags (t): ")
if input_type=="n":
input_update=raw_input("Note: ")
cursor.execute ("UPDATE notes SET note='" + sqlstr + "' WHERE id='" + input_id + "'""")
input_update=raw_input("Tags: ")
cursor.execute ("UPDATE notes SET tags='" + sqlstr + "' WHERE id='" + input_id + "'""")
print "\nRecord has been updated."

The boolbox function allows you to display a message box containing two buttons. The function returns 1 when the user presses the first button; otherwise it returns 0. Here is a simple example of how this can be used in practice:

if boolbox("What do monkeys like most?", "Pygmynote", ["Bread", "Bananas"]):
msgbox ("Well, not really.")
msgbox ("Yep, that's what they like most.")

In our case, you can use the boolbox function to prompt the user to press either the "Note" or "Tags" button and direct the script to the appropriate action:

elif command=="Update record":
input_id=enterbox(msg='Record ID: ', title='Pygmynote', default='', strip=True)
if boolbox("What do you want to update?", "Pygmynote", ["Note", "Tags"]):
input_update=enterbox(msg='Enter note: ', title='Pygmynote', default='', strip=True)
cursor.execute ("UPDATE notes SET note='" + sqlstr + "' WHERE id='" + input_id + "'""")
input_update=enterbox(msg='Enter tags: ', title='Pygmynote', default='', strip=True)
cursor.execute ("UPDATE notes SET tags='" + sqlstr + "' WHERE id='" + input_id + "'""")
msgbox ("Record has been updated.", "Pygmynote", ok_button="Close")

As the name suggests, the integerbox function displays an input box where you can enter only numeric values. It also allows you to specify the lower and upper limits for the input value. For example, you can modify the part of the Pygmynote script that displays a calendar so it prompts the user to enter a month number between 1 and 12:

inputmonth=integerbox(msg='"Month (1-12): "', title='Pygmynotes', default='', argLowerBound=1, argUpperBound=12)

EasyGui also provides the diropenbox function, which displays a directory picker dialog box. You can put this function to good use in the part of the Pygmynote script that allows the user to save all the records as a pygmynote.txt text file. The original code block saves the file in the script's directory, but using the diropenbox, you can easily give the user the ability to choose any other directory:

elif command=="Save all records as pygmynote.txt":
cursor.execute ("SELECT * FROM notes ORDER BY id ASC")
rows = cursor.fetchall ()
filedir = diropenbox(msg="Select directory", title="Pygmynote", default=None)
filename = filedir + os.sep + "pygmynote.txt"
if os.path.exists(filename):
for row in rows:
file = open(filename, 'a')
file.write("%s\t%s\t[%s]\n" % (row[0], row[1], row[2]))
msgbox ("Records have been saved in the pygmynote.txt file.", "Pygmynote", ok_button="Close")

EasyGui won't replace full-blown GUI programming kits like TKinter or wxPython, but it makes a great choice for Python newbies and coders who want to make their scripts user-friendly with a minimum of fuss. If you want to give EasyGui a try, make sure to peruse the EasyGui tutorial, which contains descriptions of other available functions.


  • Python
Click Here!