PyQt Signals & Slots

Summary: in this tutorial, you’ll learn about PyQt signals & slots and how they work in PyQt applications.

Introduction to the PyQT signals and slots

Typically, a Python script runs from the top to the bottom as follows:

  • Get inputs.
  • Process the inputs to produce outputs.
  • Write the outputs to the screen or a file.

This is called procedure programming.

When you create a GUI program, you use event-driven programming instead. In the event-driven programming paradigm, a program has the following flow:

Note that a callable is a function, a method, or an object that implements the __call__() method.

To connect events with callables of the program, PyQt uses the signals and slots mechanism.

Signals

A signal is a special property of an object that is emitted when an event occurs. An event may be a user action, a timeout, or the completion of an asynchronous operation.

Slots

A slot is a callable that can receive a signal and respond to it.

To respond to events, you connect signals to slots. When you connect a signal to a slot, the slot will be executed when the signal is emitted.

In PyQt, all subclasses of the QObject class can send and receive signals. Almost all classes in PyQt are subclasses of the QObject class.

Let’s take an example to understand how the PyQt signals & slots mechanism works.

PyQt signals & slots example

The following program displays a window that has a button. When you click the button, the program shows the clicked message in the console:

import sys
from PyQt6.QtWidgets import (
    QApplication,
    QWidget,
    QLineEdit,
    QPushButton,
    QVBoxLayout
)


class MainWindow(QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # set the window title
        self.setWindowTitle('Qt Signals & Slots')

        # create a button widget and connect its clicked signal
        # to a method
        button = QPushButton('Click me')
        button.clicked.connect(self.button_clicked)

        # place the buton on window using a vertical box layout
        layout = QVBoxLayout()
        self.setLayout(layout)

        layout.addWidget(button)

        # show the window
        self.show()

    def button_clicked(self):
        print('clicked')


if __name__ == '__main__':
    app = QApplication(sys.argv)

    # create the main window and display it
    window = MainWindow()

    # start the event loop
    sys.exit(app.exec())Code language: Python (python)

How it works. (We’ll focus on the signals & slots only)

First, create a push button using the QPushButton widget:

button = QPushButton('Click me')Code language: Python (python)

Second, connect the clicked signal to the on_clicked method (slot):

button.clicked.connect(self.button_clicked)Code language: Python (python)

In general, the syntax for connecting a signal to a slot is as follows:

sender_object.signal_name.connect(receiver_object.slot_name)Code language: Python (python)

Also, you can connect a signal to a slot when passing a slot to a signal as a keyword argument. For example:

button = QPushButton('Click me', clicked=self.button_clicked)Code language: Python (python)

Third, define a method on_clicked that prints the clicked message to the terminal:

def on_clicked(self):
    print('clicked')Code language: Python (python)

When you click the button, the QPushButton emits the clicked signal that executes the connected slot on_clicked.

Note that the following code places the button on the window using the vertical box layout. And you’ll learn more about it in the upcoming tutorial.

layout = QVBoxLayout()
self.setLayout(layout)
layout.addWidget(button)Code language: Python (python)

Using signals that send data

A signal may carry data that provides the state of the object when the event occurs. For example, the textChanged signal of the QLineEdit has the text entered in the widget.

If a signal carries data, the connected slot can receive it.

The following program shows QLineEdit and QLabel widgets. When you type something on the QLineEdit, the QLabel will display it accordingly:

import sys
from PyQt6.QtWidgets import (
    QApplication,
    QWidget,
    QLabel,
    QLineEdit,
    QVBoxLayout
)


class MainWindow(QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.setWindowTitle('Qt Signals & Slots')

        # create widgets
        label = QLabel()
        line_edit = QLineEdit()
        line_edit.textChanged.connect(label.setText)

        # place the widgets
        layout = QVBoxLayout()
        layout.addWidget(label)
        layout.addWidget(line_edit)
        self.setLayout(layout)

        # show the window
        self.show()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    sys.exit(app.exec())Code language: Python (python)

How it works.

First, create a QLabel widget. The QLabel widget has the setText() method that sets its contents.

label = QLabel()Code language: Python (python)

Second, create a new QLineEdit widget:

line_edit = QLineEdit()Code language: Python (python)

Third, connect the textChanged signal to the setText method of the QLabel object:

line_edit.textChanged.connect(label.setText)Code language: Python (python)

When you type something on the QLineEdit:

  • The textChanged signal sends the text
  • The QLabel receives the text and passes it to the setText() method.

Summary

  • A signal is a special property of an object that is emitted when an event occurs.
  • A slot is a callable that can receive a signal and respond to it accordingly.
  • PyQt uses signals and slots to wire up events with callables.
Did you find this tutorial helpful ?