Note: If you’re new to using PyQt but are interested in great cross-platform GUI application development please read the PyQt Introduction article.
Having seen how a simple PyQt application code looks, let’s delve into user-interaction. We’ll learn about Qt’s signal-to-slot connection model for processing input and other events, and layouts for proper placement of widgets on a window.
The PyQt Class Hierarchy
PyQt is completely built upon the Object-Oriented concepts, so it is important to understand how all classes are related to each other in it.
Almost all GUI classes extend upon their Abstract class which defines common behaviour for similar widgets. These abstract classes, or any widget class, inherit QWidget, the base class of all drawable GUI components. QWidget inherits QObject, a class that has nothing to do with GUI but forms the base class of every PyQt class and helps provide the framework-related features.
The following hierarchy diagram depicts this clearly for the QPushButton class:

The QPushButton Class Hierarchy
The QPaintDevice class helps draw (or paint) things on the screen, thus its also used with anything that’s drawable – We’ll learn more about Painting in a later article.
References: QWidget
Signals and Slots
All user-interaction with widgets can be performed using the concept of Signals and Slots. When a user performs an action over the widget, be it a click, a key press or even a mouse hover, an event is generated each time. These common events can be handled using the concept of signals and slots.
Basically a signal is something that’s generated each time an event occurs. The signal is ‘emitted’ by PyQt’s classes internally. To handle such signals we use the concept of slots. Each signal is given a slot to connect to. Once connected to a slot, whenever the signals are generated the slot captures it and executes a pre-specified function to process the event.
So in short words signal is something the framework emits each time an event occurs and a slot is something that receives this signal with its arguments and executes a routine.
To demonstrate the concept of signals and slots in PyQt, lets use a QPushButton along with a QWidget for the window.
The following code runs an application with a button, which when clicked upon will quit the application.
This is done by connecting the “clicked” signal of the button to the application’s “quit” slot.

Signals and Slots Example
# Program 02 - Signals
from PyQt4 import QtGui, QtCore
import sys
if __name__=='__main__':
app = QtGui.QApplication(sys.argv)
window = QtGui.QWidget()
# Create our main window using a plain QWidget.
window.setWindowTitle("Signals")
# Set our window's title as "Signals".
button = QtGui.QPushButton("Press", window)
# Create, with "Press" as its caption,
# a child button in the window.
# By specifying a parent object,
# this new widget is automatically added to the same.
button.resize(200, 40)
# Resize our button to (200, 40) -> (X, Y)
button.connect(button, QtCore.SIGNAL("clicked()"),\
app, QtCore.SLOT("quit()"))
# Connect the button's click signal to the QApplication's quit() slot.
window.show()
# Show our window.
app.exec_()
Connecting a Signal to a Slot
Connection is performed to enable particular events call their respective slots. All QObject derived classes support connections of signals and slots.
Simple syntax of the connect() method:
object.connect(Signal_Widget, Signal, Slot_Widget, Slot)
The connect() function makes a connection using two sets of parameters:
- “signal” set
- Consists of the signalling object and the type of signal you wish to handle (Given by SIGNAL(QString)).
- Every widget emits a signal upon an event like a user interaction or timer generated.
- These signals are not to be confused with POSIX/UNIX signals, that’s a wholly different OS-level concept.
- “slot” set
- The receiving object, and the slot it must execute upon the signal (Given by SLOT(QString)).
- Every emitted signal can be handled by a function, called in PyQt-lingo as a “slot”.
- A slot is executed each time the signal connected to it is emitted by the signalling class.
QtCore.QObject is the class that provides us the connect function you used. Since our class is derived from QObject, we can also use it from it’s instance. This means that the 20th line can be replaced with:
QtCore.QObject.connect(button, QtCore.SIGNAL("clicked()"),\
app, QtCore.SLOT("quit()"))
A PyQt widget has many signals and slots. For example a QAbstractButton has clicked(), pressed(), released() and toggled() signals and click(), setChecked(Bool), toggle() slots. PyQt pre-provides most of the GUI functionality needs one can think of.
References: QObject | Signals and Slots | QPushButton | QApplication
Layouts
If you tried stretching the previous example’s window a bit, you would feel that the button is more pasted onto the window than placed. It does not move from its position, the window contents don’t mutate based on the user’s screen. Layouts help in this aspect and more.
As the word means, Layouts help lay out your widgets on the form/window in a proper manner. QLayout forms the most basic Layout class and has four major layout sub-classes. The types of those are Box, Grid, Form and Stacked layouts. The following depicts the hierarchy of these layouts, and how some of these look.

PyQt Layouts Hierarchy
Using a Layout is simple in PyQt. One only has to attach the preferred layout to a window/widget and then adding the components to it (the layout) will automatically lay them out. The following topic’s example makes use of the QHBoxLayout.

Various PyQt Layouts - Each square can contain an item.
References: QLayout | Layout Classes
Passing Arguments to Slots
Signals and Slots can also carry parameters. This is useful when there’s an input involved, or when there needs to be some data sent automatically each time an event occurs.
Let me demonstrate another example, one with parameters. In this example I shall connect a line editor to a label, and as one enters text into the line editor events are generated that make a slot of the label execute and change its display text to the one you’ve typed. For this we need to use a QLabel for the label and a QLineEdit for the line editor.
List of steps to write the code below:
- Import necessary classes and functions from PyQt4 (QtGui and QtCore).
- Create the QApplication instance.
- Create a Window (QWidget).
- Attach a QHBoxLayout to it (By setting Window as its parent).
- Create a Line input widget and add it to the layout.
- Create a Label widget and add it to the layout.
- Connect the textChanged(QString) signal of the QLineEdit to the setText(QString) slot of QLabel.
- Show the Window.
- Begin the Application loop.

Signals and Slots with Arguments Example
# Program 03 - Signals and Slots with Arguments
from PyQt4.QtCore import SIGNAL, SLOT
from PyQt4.QtGui import QApplication, QWidget,\
QLineEdit, QLabel, QHBoxLayout
import sys
if __name__=='__main__':
App = QApplication(sys.argv)
Window = QWidget()
Window.setWindowTitle("Arguments")
Layout = QHBoxLayout(Window)
# Create a Layout Object, attached to the Window.
Line = QLineEdit()
# Create a Line-Editor / Text-Box.
Layout.addWidget(Line)
# Add it to the HBox Layout.
Label = QLabel()
Layout.addWidget(Label)
Line.connect(Line, SIGNAL("textChanged(QString)"),\
Label, SLOT("setText(QString)"))
# Connect the required signal and slot.
Window.show()
App.exec_()
When the user enters/modifies the text of the QLineEdit widget a textChanged(QString) signal is emitted with the new modified string loaded into it. We intercept this and connect it to the QLabel’s setText(QString) function/slot. Thus the changed QString travels from the QLineEdit to QLabel and is set for display, all upon a single character modification!
The Layout part (Lines 11, 15, 18) has an interesting function addWidget() that takes a widget and adds it to the layout geometry. The addWidget method also takes a stretch-factor and an alignment factor as its parameters, along with a QWidget/derivative. The layout automatically adjusts the widget sizes based on the text input in this example. If you increase the window size, the layout makes it adapt to the same – try it out to understand!
If the signal/slot concept still sounds confusing, the following graphic will clear it up a little more.

Signals and Slots in the Arguments example
So that’s it about Signals, Slots and Layouts!
References: QLineEdit | QLabel | QHBoxLayout
Writing Custom Signals
This is a slightly advanced topic covered in my PyQt FAQ post. Click here to read more on how to write custom Signals with PyQt.
Exercise
Use a QPushButton in a QWidget window and toggle its text each time its clicked. Also, add a layout to the window with the button in it.
Each time the button is clicked, its text must toggle. For example, if the Button’s text is Hello, after a click it changes to PyQt and another click makes it Hello back again. Ensure that the button gets expanded as the window it is in grows.
Footnotes:
- You can pass a function directly to the connect() too, for slot-purposes. It needn’t be a PyQt-provided slot always.
- We can also write custom signals and slots for certain events, how awesome is that? I will cover it when we begin to write our own PyQt Classes.
- Not all GUI components have an Abstract class. They exist only for a widget or an item that can be extended in more ways than one.
P.s. While commenting on this article, do nest the code in <pre> and </pre> tags.
I had done a bit of GTK+ coding a few months back and the flow of things that you are following are pretty much the same that i followed then. Nice. The article itself is pretty good. The diagrams are self explanatory and help a lot. At the risk of sounding like a n00b i would suggest at u put up a list of packages to get he PyQt devel environment up and running. Sometimes this can be a pain. Sometimes. Keep the articles coming.
Chinmay Kamat
14 May 09 at 7:18 pm
Packages in Linux get vague with the distribution, but anyway, on Ubuntu you would need the python-qt4-dev and the pyqt4-dev-tools packages.
Basically, look for packages that provide:
Follow the official installation guide at Riverbank if you want to build it from scratch, since it varies from platform to platform. Hard to cover all, and since all guides are present at their respective developer websites why not follow them!
About an Editor, use the one you’re comfortable with. For an IDE you can choose Eric4 or PyDev(Eclipse). There are a few more, and Google should help there
Windows should have an easier installer solution and I haven’t much clue on the OS X front
Harsh
14 May 09 at 9:13 pm
@cdk, he is doing great job. QwertyM is. Stop finding or trying to find problems with the article.
Aditya
15 May 09 at 11:31 am
No one’s done the takeaway problem?
Harsh
18 May 09 at 6:58 pm
These tutorials are, so far, amazing. Thank you.
10
6 Jun 09 at 11:06 pm
Thank you for your comment
The next article, about Designer, should be up in a couple of days
Harsh
7 Jun 09 at 12:35 pm
Hi,
I am a newbie, working on developing a GUI with PyQT. I tried your exercise. ^ ^
But somehow the slot doesn’t work, and the text on my pushbutton does not even change, let alone toggle. > <
from PyQt4.QtCore import SIGNAL, SLOT
from PyQt4.QtGui import QApplication, QWidget, QPushButton, QLabel, QVBoxLayout
import sys
if __name__==’__main__’:
App = QApplication(sys.argv)
Window = QWidget()
Window.setWindowTitle(“PushButton Toggle Exercise”)
Layout = QVBoxLayout(Window)
Button = QPushButton()
Button.setText(‘Default’)
Layout.addWidget(Button)
MyString = ‘Welcome!’
Button.connect(Button, SIGNAL(“pressed()”), Button, SLOT(“setText(MyString)”))
Window.show()
App.exec_()
Helvin
3 Jul 09 at 4:00 am
Waiting for your PyQt tutorials. Keep them coming PLEASE!
Helvin
3 Jul 09 at 4:14 am
I am not sure what character Helvin is using, but it does not appear to be a single quote, because the interactive python interpreter on my box won’t accept it. I presume that is the problem with the code from July of last year that nobody responded to…
File “”, line 1
if __name__==’__main__’:
^
SyntaxError: invalid syntax
Gordonian
31 Oct 10 at 7:31 pm
Yep, looks like my CMS played funny while translating that code for formatting in comments. (One could use pre tags though).
But anyways, that line isn’t needed in interpreter mode.
Harsh
7 Nov 10 at 11:23 am
For the purpose fo the exercise, is there some way I can read the text of the button?
I tried the following:
from PyQt4.QtGui import QWidget, QPushButton, QHBoxLayout, QApplication
from PyQt4.QtCore import SIGNAL, SLOT
import sys
if __name__==’__main__’:
app = QApplication(sys.argv)
window = QWidget()
window.setWindowTitle(“Layouts Ex. 1″)
button = QPushButton(“Hello”)
layout = QHBoxLayout(window)
def toggle():
if button["text"] == “Hello”:
return “PyQt”
else:
return “Hello”
layout.addWidget(button)
button.connect(button, SIGNAL(“clicked()”),\
button, SLOT(“setText(toggle())”))
window.show()
app.exec_()
Obviously it doesn’t work, for one or both of these reasons:
- button["text"] doesn’t return the text of the button (it was a complete guess as I couldn’t figure out where to find this info in the docs)
- maybe you can’t call a function in a slot like I tried to do with toggle()
Can you give me a pointer?
-Blahah
p.s. nice tutorial thanks, PyQt and python really starting to make sense after reading through your articles.
Blahah
28 Jan 11 at 11:07 pm
Hey Blahah,
QAbstractButton.text() returns the QString text. Note that all properties of a class available in Qt can be got via property() and set via setProperty() [No 'get' business, like in Java]
2nd point is right. Registered slots of a class have a ‘signature’, (as in, “clicked()”, etc.), so you can’t push in functions into them to execute. Try the same approach by extending the class QPushButton and adding in a new method inside, instead of using an external function. This way you’d also learn how to extend/improve base Qt classes for your needs, as is the philosophy
Harsh
30 Jan 11 at 9:56 pm
Thanks for the feedback, I think I’m making progress here… (I’m a newbie at programming/python/PyQt)
Trying to take on board your advice, I came up with this:
from PyQt4.QtGui import QWidget, QPushButton, QHBoxLayout, QApplication
from PyQt4.QtCore import SIGNAL, SLOT
import sys
if __name__==’__main__’:
app = QApplication(sys.argv)
window = QWidget()
window.setWindowTitle(“Layouts 1″)
button = QPushButton(“Hello”)
layout = QHBoxLayout(window)
class Toggle(QPushButton):
def toggleText(self):
if button.text() == “Hello”:
button.setText(“PyQt”)
else:
button.setText(“Hello”)
layout.addWidget(button)
button.connect(button, SIGNAL(“clicked()”),\
button, SLOT(“toggleText()”))
window.show()
app.exec_()
The program runs with the error ‘No such slot QPushButton::toggleText()’.
Have I extended the class correctly? Do I need to define an __init__ for my class? Sorry for coming back for more help, it’s quite baffling trying to get my head around the documentation.
Blahah
2 Feb 11 at 10:57 pm
Hi again Harsh. I *finally* got this to work:
from PyQt4.QtGui import QWidget, QPushButton, QHBoxLayout, QApplication
from PyQt4.QtCore import SIGNAL, SLOT
import sys
if __name__==’__main__’:
app = QApplication(sys.argv)
window = QWidget()
button = QPushButton(“Hello”)
layout = QHBoxLayout(window)
layout.addWidget(button)
def toggler():
if button.text() == “Hello”:
button.setText(“PyQt”)
else:
button.setText(“Hello”)
button.connect(button, SIGNAL(“clicked()”), toggler)
window.show()
app.exec_()
But I can’t make it work without the toggler() function explicitly referring to the button instance. I wanted to make it so the toggler function was passed the name of the instance by the signal.
I tried:
def toggler(x):
if x.text() == “Hello”:
x.setText(“PyQt”)
else:
x.setText(“Hello”)
button.connect(button, SIGNAL(“clicked()”), toggler(button))
I don’t understand why I can’t do this, and what I would have to do differently to make it work.
Sorry for flooding your comments recently, but hey at least you know your blog is teaching someone PyQt
Blahah
5 Feb 11 at 7:40 pm
Also, I tried to extend the class as per your instructions but I couldn’t work out how to register a function of a class as a slot – there seem to be two different signal/slot systems in PyQt and neither specifies how to do this in the docs.
Blahah
5 Feb 11 at 7:45 pm
@Blahah – All methods are usable as slots without needing a ‘registration’ of any kind (You do need registrations for signals, however).
For a deeper example, check this. Hope that helps clear your instance issue
Harsh
6 Feb 11 at 1:33 am
I realised the problem as soon as I read your reply – “all *methods* are usable as slots”. I had created a class which extended QPushButton, but then I didn’t create an instance of my class. So I thought I was trying to call a function – I should have been calling the method of my instance.
Note to self: always work with instances!
Thanks for all the help, Harsh.
Blahah
6 Feb 11 at 1:39 am
Yes, in a Python class, you always work with the method’s first argument (being the instance) – generally referred to as ‘self’.
Harsh
8 Feb 11 at 9:15 am