How to Find What Data a Signal Sends in PyQt6 and PySide6

Understanding signal signatures and how to look them up in the Qt documentation
Heads up! You've already completed this tutorial.

When connecting a signal to a slot, how do you know what data the signal passes along? For example, windowTitleChanged sends a string — but how would you find that out? With so many different signals in Qt (pressed, released, drag, move, etc.), how do we know what each signal sends when it's triggered?

When you first start working with signals and slots in PyQt6 or PySide6, the mechanism itself is fairly intuitive: something happens, and your connected function gets called. But at some point you'll notice that some signals pass data to your slot function, and you might wonder — where does that data come from, and how do I know what to expect?

Let's look at a quick example to set the scene:

python
self.windowTitleChanged.connect(self.on_window_title_change)

def on_window_title_change(self, s):
    print(s)

Here, windowTitleChanged is a signal that gets emitted whenever the window title changes. It sends the new title as a string to whatever slot is connected. But how would you know that s is a string? And how do you figure this out for any signal?

The answer is: the Qt documentation.

Reading the Qt documentation

Every signal in Qt has a signature — a definition that tells you the name of the signal and what types of data it sends. You can find these signatures in the official Qt documentation.

For PySide6, the documentation lives at:

📄 https://doc.qt.io/qtforpython-6/

For PyQt6, you can use the main Qt C++ documentation (the signal signatures are the same):

📄 https://doc.qt.io/qt-6/

Let's walk through how to look up a signal.

Looking up windowTitleChanged

The windowTitleChanged signal belongs to QWidget. If you search for QWidget in the Qt documentation, you'll find a page listing all its signals. Under the signals section, you'll see something like:

python
windowTitleChanged(const QString &title)

In the PySide6 documentation, this looks like:

python
windowTitleChanged(title)

with the parameter type listed as str.

This tells you that when the signal is emitted, it sends one piece of data: a string containing the new window title. That string is what arrives as the s parameter in your slot function.

What a signal signature tells you

A signal signature gives you two things:

  1. How many parameters the signal sends (zero, one, or more).
  2. What type each parameter is.

Here are a few common examples to give you a feel for the patterns:

Signal Belongs to Signature What it sends
clicked QPushButton clicked(checked: bool) Whether the button is checked (for checkable buttons)
textChanged QLineEdit textChanged(text: str) The new text in the input field
valueChanged QSpinBox valueChanged(value: int) The new integer value
currentIndexChanged QComboBox currentIndexChanged(index: int) The index of the newly selected item

Some signals send no data at all. For example, QPushButton.pressed has an empty signature — it just tells you "the button was pressed" without any additional information. Your slot function doesn't need any parameters in that case.

Connecting signals with and without data

When a signal sends data, your slot function needs a parameter to receive it. When it doesn't, you leave the parameter out.

Here's a complete example showing both cases:

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


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Signal Signatures")

        layout = QVBoxLayout()

        # QPushButton.pressed sends no data
        button = QPushButton("Click me")
        button.pressed.connect(self.on_button_pressed)
        layout.addWidget(button)

        # QLineEdit.textChanged sends a string
        line_edit = QLineEdit()
        line_edit.textChanged.connect(self.on_text_changed)
        layout.addWidget(line_edit)

        container = QWidget()
        container.setLayout(layout)
        self.setCentralWidget(container)

    def on_button_pressed(self):
        # No parameters — pressed sends nothing
        print("Button was pressed!")

    def on_text_changed(self, text):
        # One parameter — textChanged sends the new text as a string
        print(f"Text changed to: {text}")


app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()

Run this and try clicking the button and typing in the text field. You'll see the pressed signal triggers with no data, while textChanged passes along the current text each time it changes.

Signals with multiple parameters

Some signals send more than one piece of data. For example, QTableWidget.cellChanged sends both the row and column of the changed cell:

python
cellChanged(row: int, column: int)

Your slot would look like:

python
def on_cell_changed(self, row, column):
    print(f"Cell at row {row}, column {column} changed")

Each parameter in the signal signature maps to a parameter in your slot function, in order.

A quick way to explore: just print it

If you're ever unsure what a signal is sending, you can connect it to a quick test function that prints whatever it receives. Python's *args syntax is helpful for this:

python
def debug_slot(*args):
    print(args)

some_widget.some_signal.connect(debug_slot)

This will print a tuple of everything the signal sent. It's a handy way to explore while you're developing, even if you wouldn't leave it in production code.

Where to look things up

To summarize, when you want to know what a signal sends:

  1. Identify which class the signal belongs to. For example, textChanged on a QLineEdit belongs to QLineEdit.
  2. Search for that class in the Qt documentation. Look in the "Signals" section of the class page.
  3. Read the signal signature. It tells you the number and types of parameters.

For PySide6, the Qt for Python documentation shows Python types directly. For PyQt6, the main Qt docs use C++ types, but the mapping is straightforward: QStringstr, intint, boolbool, doublefloat, and so on.

Over time, you'll start to remember the common ones — clicked sends a bool, textChanged sends a str, valueChanged sends an int or float depending on the widget. But whenever you encounter a new signal, the documentation is always there to check.

Complete working example

Here's a fuller example that demonstrates several different signal signatures in one window:

python
from PyQt6.QtWidgets import (
    QApplication, QMainWindow, QPushButton, QLineEdit,
    QSpinBox, QComboBox, QVBoxLayout, QWidget, QLabel
)
import sys


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Exploring Signal Signatures")

        layout = QVBoxLayout()

        self.output_label = QLabel("Interact with the widgets below:")
        layout.addWidget(self.output_label)

        # QPushButton — clicked sends a bool (checked state)
        button = QPushButton("Click me")
        button.setCheckable(True)
        button.clicked.connect(self.on_button_clicked)
        layout.addWidget(button)

        # QLineEdit — textChanged sends a str
        line_edit = QLineEdit()
        line_edit.setPlaceholderText("Type something...")
        line_edit.textChanged.connect(self.on_text_changed)
        layout.addWidget(line_edit)

        # QSpinBox — valueChanged sends an int
        spinbox = QSpinBox()
        spinbox.setRange(0, 100)
        spinbox.valueChanged.connect(self.on_value_changed)
        layout.addWidget(spinbox)

        # QComboBox — currentIndexChanged sends an int
        combo = QComboBox()
        combo.addItems(["Apple", "Banana", "Cherry"])
        combo.currentIndexChanged.connect(self.on_index_changed)
        layout.addWidget(combo)

        # windowTitleChanged sends a str
        self.windowTitleChanged.connect(self.on_title_changed)

        container = QWidget()
        container.setLayout(layout)
        self.setCentralWidget(container)

    def on_button_clicked(self, checked):
        self.output_label.setText(
            f"Button clicked — checked: {checked} (bool)"
        )

    def on_text_changed(self, text):
        self.output_label.setText(
            f"Text changed — value: '{text}' (str)"
        )

    def on_value_changed(self, value):
        self.output_label.setText(
            f"SpinBox changed — value: {value} (int)"
        )

    def on_index_changed(self, index):
        self.output_label.setText(
            f"ComboBox changed — index: {index} (int)"
        )

    def on_title_changed(self, title):
        print(f"Window title changed to: '{title}' (str)")


app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()

Try interacting with each widget and watch the label update. Each slot receives exactly the data described by that signal's signature in the documentation — no more, no less. Once you get comfortable checking the docs, you'll always know what to expect.

Well done, you've finished this tutorial! Mark As Complete
[[ user.completed.length ]] completed [[ user.streak+1 ]] day streak

Packaging Python Applications with PyInstaller by Martin Fitzpatrick

This step-by-step guide walks you through packaging your own Python applications from simple examples to complete installers and signed executables.

More info Get the book

Martin Fitzpatrick

How to Find What Data a Signal Sends in PyQt6 and PySide6 was written by Martin Fitzpatrick.

Martin Fitzpatrick has been developing Python/Qt apps for 8 years. Building desktop applications to make data-analysis tools more user-friendly, Python was the obvious choice. Starting with Tk, later moving to wxWidgets and finally adopting PyQt. Martin founded PythonGUIs to provide easy to follow GUI programming tutorials to the Python community. He has written a number of popular Python books on the subject.