Tutorial: Creating GUI Applications in Python with QT
by Alex Fedosov

Python is a great language with many awesome features, but its default GUI package (TkInter) is rather ugly. Besides, who wants to write all that GUI code by hand, anyway? Instead, a much better way to write GUI apps in Python is to use Trolltech's QT Designer to WYSIWYG-ly create a nice-looking interface, and then automatically generate the necessary code for it with pyuic (which is a UI compiler for QT that comes with the PyQT package.) QT designer also makes it very easy to add Python code to your project. (If you want your app to do anything useful, you will undoubtedly need to write some code. :) )

So the following is a brief tutorial on how to go about creating your first semi-interesting application with Python & QT.

We are going to create a little application that will take input from the user, add said input to a list box and also allow the user to clear the contents of the list box.

First, you need to have the following packages installed:

I did everything with default packages that came with Fedora Core 1, and had no problems. Also tested on RedHat 9 with no problems. YMMV. (Note: RedHat 8.0 should also work, but it has an older version of QT designer, which is not as nice as the one in RH9 and FC1.)
So if you have everything, we can go ahead and get started. Launch QT designer. In RedHat 9 and Fedora Core 1, it lives under Programming/More Programming menu.



QT Designer will come up. It looks like this.

In the New/Open dialog box, click on Dialog, and hit OK.



QT Designer will create a new dialog canvas for you and call it Form1.



In the toolbar on the left select the LineEdit tool and create an edit box on the canvas. Its name will be lineEdit1. This is how we will take input from the user.



Now, select the ListBox tool in the toolbar on the left and create a list box on the canvas. Its name will be listBox1. This is where we will store the input that the user typed in.



Notice that there is already an item in the box. We don't need it. Let's get rid of it. Double-click on your list box on the canvas. A dialog will pop up showing the contents of the list box. Hit Delete Item to get rid of the item. Then click OK.



Now, select the PushButtontool in the toolbar on the left and create a button on the canvas. Its name will be pushButton1.



Double-click on the button on the canvas. A dialog will come up where you can change the text displayed on the button. Let's rename it to X. Then click OK.



Now, let's make the button do something. In QT terminology, our button will send a signal which will be received by a slot. (Think of a slot as a method of an object that will get called in response to an event, like user clicking the button.) Remember that we want to clear the list box when the user clicks the button. There are already built-in methods for this, so we'll take advantage of them. To connect a signal to a slot we use the connect tool which is the red arrow on the green rectange in the top toolbar on the right. It looks like this:


Here's the tricky part. After selecting the tool, click on your X button on the canvas, and drag the mouse (without releasing) to your listbox on the canvas. Once you are over the listbox (it will be highlighted), you will see a line from the button to the listbox, and you can release the mouse. Another dialog box will pop up where you can specify exactly which signal and slot you want to connect. Select pushButton1 as the sender, clicked() as the signal, listBox1 as the receiver and clear() as the slot. Then click OK. (The meaning of this is that we want to delete all contents of the box when the user clicks the button.)



In the previous step, we used a built-in slot to accomplish something. Now, let's create our own slot, which will take input from the edit box and add it to the list box when the user presses enter after typing something. To create a new slot (remember, it's just a method), select Slots from the Edit menu.



A dialog listing custom slots will show up. Initially, it will be empty. Let's add a new slot by clicking New Function. Let's call this function AddEntry() (don't forget the parentheses when typing in the new name) because it will add a new item to the list box. Don't change any other settings and just click OK. (We'll write the code for this method later on.)



Now that we have a slot, we can connect something to it. Recall that we want to add an item to the list when the user types something in the edit box and presses Enter. Select our good friend the connect tool and now connect the line edit to the list box. The connection dialog will pop up again. This time select lineEdit1 as the sender, returnPressed() as the signal, Form1 as the receiver, and our own AddEntry() as the slot.



Finally, we are ready to write some code. We need to implement our AddEntry() method. In the Project Overview window in the top right-hand corner, double-click on the form1.ui.h file. (The second one, under your main file.) A window will pop up showing the text of this file. This file is where you implement all your custom slots, which will then be included during the compilation process. Notice that QT designer already put in a header for our AddEntry() function... except that it's in C++! Don't worry about that, however, we can still write Python code here right between the braces, and it will work just fine. (Python UI compiler is smart enough to understand the headers generated by QT designer.) The only problem is that QT designer wants to auto-indent your code, but it expects semi-colons at the end of line, so naturally Python confuses it and the indentation gets all screwed up. So alternatively, you can just use your favorite editor (read: vi) to edit this file. (Or figure out how to turn off auto-indent.)



So what code do we write? We need to accomplish three things:
All the slots you define are methods of the dialog box, and all your widgets are objects within it, and you can just refer to them by their names. So self.lineEdit1 is the line edit, and self.listBox1 is the list box. The line edit has a method called text() which returns a QString object representing the text in the line edit. Without going into too much details about these objects, all we need to know is that a QString object has an ascii() method which will return the raw ASCII string of the entered text. So to get the text out of the list box:
e = self.lineEdit1.text().ascii()


Next thing we need to do is add this text to the list box. The list box has a method insertItem() which takes a string and adds it to the list:
self.listBox1.insertItem(e)
Finally, we just clear the line edit with its clear() method:
self.lineEdit1.clear()




Almost done! Last thing we need to do is to turn off the autoDefault setting for our delete button. (Setting a button as default means that it will get 'clicked' if the user presses Enter on the dialog. For us it would not make sense to add text to the list box on Enter, and then have the delete button automatically triggered, clearing our list box.) The autoDefault property is True by default, so we need to set it to False in the Property Editor window for the button. Click on the button to see the Property window for it in the lower right-hand corner.



Finally we are done with QT designer. Save all your work.


Now open up a shell. We want to compile our GUI code into Python code. This is done for us by the pyuic compiler. Pass the .ui file as an argument, and it will spit out Python code onto standard output. (So it's more useful to redirect the output to another file.)
pyuic form1.ui > form1.py

Now you end up with form1.py which is a module containing your dialog as a Python class. Since it has no main() function, you can't run it directly. Instead, we need to create a simple wrapper for it, like so:

from qt import *
from form1 import *
import sys
if __name__ == "__main__":
    app = QApplication(sys.argv)
    f = Form1()
    f.show()
    app.setMainWidget(f)
    app.exec_loop()

Without going into too much detail, we import the QT library Python module, as well as our dialog class. Then we create a context for our QT application, instantiate our dialog, show it on the screen, set it as the main widget of the application, and let QT enter its event loop, processing all the signals and calling our slots. Save this in a separate Python file, e.g. mygui.py. Needless to say, this wrapper is fairly generic and can be reused for most of your Python/QT applications. Finally, we are ready to run! Execute your app with:
python mygui.py

It should look something like this:



If you type something into the line edit box and press Enter, it should get added to the list box. If you hit the X button, the list box should be cleared. If it doesn't behave as it should, go back and re-read the steps, you probably missed something. :)

Well, that's about it. Now go create something more fun! Except you probably want to know about all these widgets and all their methods. How do we know who does what? The easiest way to find out is to read the QT Classes Reference (or the Main QT Reference page) that describes all the QT classes (including all the widgets) and their methods and properties. Their examples are in C++, but they translate very well into Python. All the names are exactly the same -- just replace C++ syntax with Python, and you are good to go!

Files used in this project
form1.ui
form1.ui.h
mygui.py

As an exercise, add some Python code that saves the contents of the list box to a file on exit, and then loads the data from the file at startup.

Good luck, have fun, and I hope my tutorial has helped you out somewhat.