![]() |
|||||||||||
|
programming Qt applications in pythonStep 1: simple hello worldStep 2: a button Step 3: a more structured approach Step 4: using Qt designer This tutorial aims to provide a hands-on guide to learn the basics of building a small Qt application in python. To follow this tutorial, you should have basic python knowledge, knowledge of Qt, however, is not necessary. I'm using Linux in these examples and am assuming you already have a working installation of python and pyqt. To test that, open a python shell by simply typing python in a console to start the interactive interpreter and type >>> import qtIf this doesn't yield an error message, you should be ready to roll. The examples in this tutorial are kept as easy as possible, showing useful ways to write and structure your program. It is important that you read the source code of the example files, most of the stuff that is done is explained in the code. Use the examples and try to change things, play around with them. This is the best way to get comfortable with it. Hello, world!Let's start easy. Popping up a window and displaying something. The following small program will popup a window showing "Hello world!", obviously.
#!/usr/bin/env python
import sys
from qt import *
# We instantiate a QApplication passing the arguments of the script to it:
a = QApplication(sys.argv)
# Add a basic widget to this application:
# The first argument is the text we want this QWidget to show, the second
# one is the parent widget. Since Our "hello" is the only thing we use (the
# so-called "MainWidget", it does not have a parent.
hello = QLabel("Hello world!",None)
# We have to let the application know which widget is its MainWidget ...
a.setMainWidget(hello)
# ... and that it should be shown.
hello.show()
# Now we can start it.
a.exec_loop()
download source of hello.py
About 7 lines of code, and that's about as easy as it can get. A buttonLet's add some interaction! We'll replace the label saying "Hello, World!" with a button and assign an action to it. This assignment is done by connecting a signal, an event which is sent out when the button is pushed to a slot, which is an action, normally a function that is run in the case of that event.
#!/usr/bin/env python
import sys
from qt import *
a = QApplication(sys.argv)
# Our function to call when the button is clicked
def sayHello():
print "Hello, World!"
# Instantiate the button
hellobutton = QPushButton("Say 'Hello world!'",None)
# And connect the action "sayHello" to the event "button has been clicked"
a.connect(hellobutton, SIGNAL("clicked()"), sayHello)
# The rest is known already...
a.setMainWidget(hellobutton)
hellobutton.show()
a.exec_loop()
download source of hellobutton.py
Urgh, that looks like a crappy approachYou can imagine that coding this way is not scalable nor the way you'll want to continue working. So let's make that stuff pythonic, adding structure and actually using object-orientation in it. We create our own application class, derived from a QApplication and put the customization of the application into its methods: One method to build up the widgets and a slot which contains the code that's executed when a signal is received.
#!/usr/bin/env python
import sys
from qt import *
class HelloApplication(QApplication):
def __init__(self, args):
""" In the constructor we're doing everything to get our application
started, which is basically constructing a basic QApplication by
its __init__ method, then adding our widgets and finally starting
the exec_loop."""
QApplication.__init__(self, args)
self.addWidgets()
self.exec_loop()
def addWidgets(self):
""" In this method, we're adding widgets and connecting signals from
these widgets to methods of our class, the so-called "slots"
"""
self.hellobutton = QPushButton("Say 'Hello world!'",None)
self.connect(self.hellobutton, SIGNAL("clicked()"), self.slotSayHello)
self.setMainWidget(self.hellobutton)
self.hellobutton.show()
def slotSayHello(self):
""" This is an example slot, a method that gets called when a signal is
emitted """
print "Hello, World!"
# Only actually do something if this script is run standalone, so we can test our
# application, but we're also able to import this program without actually running
# any code.
if __name__ == "__main__":
app = HelloApplication(sys.argv)
download source of helloclass.py
(Note that the above code shows exactly the same as the second example, but it's scalable.
gui coding sucks
... so we want to use Qt3 Designer for creating our GUI. In the picture, you can see a simple GUI, with in green letters the names of the widgets. What we are going to do is
pyuic testapp_ui.ui -o testapp_ui.pymakes a python file from it which we can work with. The way our program works can be described like this:
#!/usr/bin/env python
from testapp_ui import TestAppUI
from qt import *
import sys
class HelloApplication(QApplication):
def __init__(self, args):
""" In the constructor we're doing everything to get our application
started, which is basically constructing a basic QApplication by
its __init__ method, then adding our widgets and finally starting
the exec_loop."""
QApplication.__init__(self,args)
# We pass None since it's the top-level widget, we could in fact leave
# that one out, but this way it's easier to add more dialogs or widgets.
self.maindialog = TestApp(None)
self.setMainWidget(self.maindialog)
self.maindialog.show()
self.exec_loop()
class TestApp(TestAppUI):
def __init__(self,parent):
# Run the parent constructor and connect the slots to methods.
TestAppUI.__init__(self,parent)
self._connectSlots()
# The listview is initially empty, so the deletebutton will have no effect,
# we grey it out.
self.deletebutton.setEnabled(False)
def _connectSlots(self):
# Connect our two methods to SIGNALS the GUI emits.
self.connect(self.addbutton,SIGNAL("clicked()"),self._slotAddClicked)
self.connect(self.deletebutton,SIGNAL("clicked()"),self._slotDeleteClicked)
def _slotAddClicked(self):
# Read the text from the lineedit,
text = self.lineedit.text()
# if the lineedit is not empty,
if len(text):
# insert a new listviewitem ...
lvi = QListViewItem(self.listview)
# with the text from the lineedit and ...
lvi.setText(0,text)
# clear the lineedit.
self.lineedit.clear()
# The deletebutton might be disabled, since we're sure that there's now
# at least one item in it, we enable it.
self.deletebutton.setEnabled(True)
def _slotDeleteClicked(self):
# Remove the currently selected item from the listview.
self.listview.takeItem(self.listview.currentItem())
# Check if the list is empty - if yes, disable the deletebutton.
if self.listview.childCount() == 0:
self.deletebutton.setEnabled(False)
if __name__ == "__main__":
app = HelloApplication(sys.argv)
download source of testapp.py
download ui file testapp_ui.ui
download compiled ui testapp_ui.py
useful to knowCreating the GUI in Qt designer does not only make it easier creating the GUI, but it's a great learning tool, too. You can test how a widget looks like, see what's available in Qt and have a look at properties you might want to use.The C++ API documentation is also a very useful (read: necessary) tool when working with PyQt. The API is translated pretty straightforward, so after having trained a little, you'll find the developers API docs one of the tools you really need. When working from KDE, konqueror's default shortcut is qt:[widgetname], so [alt]+[F2], "qt:qbutton directly takes you to the right API documentation page. Trolltech's doc section has much more documentation which you might want to have a look at. The examples in this tutorial have been created using Qt 3.3. I might update the tutorial when there's a usable version of the Qt bindings for Qt 4 available, but at this moment, using PyQt4 does not make sense. This document is published under the GNU Free Documentation License.
07-12-2005, 19:22 h
© Sebastian Kügler |
||||||||||
|
|||||||||||