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.
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:
Grab the text from the line edit
Insert the text into the list box
Clear the line edit
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.
|