PyQt6 is a powerful library for creating desktop GUI applications in Python.
A core concept in PyQt6 is signals and slots, which is a mechanism for communication between objects.
This allows one object to notify another about events or changes in state.
In this tutorial, we’ll cover:
1. Introduction to Signals and Slots
A signal is emitted when an event occurs, such as clicking a button. A slot is a method that is called in response to a signal.
Key Points
- Signals are predefined or custom events.
- Slots are any Python callable (function, method, etc.).
- PyQt6 uses the @pyqtSlot decorator to define slots, though this is optional.
2. Connecting Signals to Slots
To connect a signal to a slot, use the .connect() method.
Example: Button Click Signal
import sys from PyQt6.QtWidgets import QApplication, QPushButton, QVBoxLayout, QWidget class MainWindow(QWidget): def __init__(self): super().__init__() self.setWindowTitle("Signals and Slots Example") # Create a button self.button = QPushButton("Click Me!") # Connect the button's clicked signal to a slot self.button.clicked.connect(self.on_button_clicked) # Set layout layout = QVBoxLayout() layout.addWidget(self.button) self.setLayout(layout) def on_button_clicked(self): print("Button was clicked!") # Application setup app = QApplication(sys.argv) window = MainWindow() window.show() sys.exit(app.exec())
When the button is clicked, the on_button_clicked slot is triggered, printing a message to the console.
3. Creating Custom Signals
Custom signals allow you to define specific events. Use the pyqtSignal class from PyQt6.QtCore.
Example: Custom Signal
from PyQt6.QtCore import pyqtSignal, QObject class Communicator(QObject): # Define a custom signal custom_signal = pyqtSignal(str) class Receiver: def slot_function(self, message): print(f"Received message: {message}") # Usage sender = Communicator() receiver = Receiver() # Connect the custom signal to the receiver's slot function sender.custom_signal.connect(receiver.slot_function) # Emit the signal sender.custom_signal.emit("Hello, PyQt6!")
In this example:
- custom_signal is a signal that carries a str argument.
- slot_function is the slot that receives and processes the signal.
4. Disconnecting Signals
You can disconnect a signal from a slot using the .disconnect() method.
Example: Disconnecting Signals
class Test(QObject): signal = pyqtSignal() def example_function(): print("Signal received.") # Create objects test = Test() # Connect and disconnect test.signal.connect(example_function) test.signal.disconnect(example_function) # Emit the signal (this will do nothing as it's disconnected) test.signal.emit()
5. Practical Examples
Example 1: Passing Data with Signals
from PyQt6.QtWidgets import QLabel, QLineEdit, QVBoxLayout, QWidget, QApplication from PyQt6.QtCore import pyqtSignal class DataEmitter(QWidget): data_signal = pyqtSignal(str) # Signal carrying string data def __init__(self): super().__init__() self.setWindowTitle("Passing Data with Signals") # Widgets self.input = QLineEdit(self) self.label = QLabel("Type something:", self) # Layout layout = QVBoxLayout() layout.addWidget(self.input) layout.addWidget(self.label) self.setLayout(layout) # Connect input's textChanged signal to the custom signal self.input.textChanged.connect(self.emit_data) # Connect custom signal to the label's slot self.data_signal.connect(self.update_label) def emit_data(self, text): self.data_signal.emit(text) def update_label(self, text): self.label.setText(f"You typed: {text}") # Application setup app = QApplication([]) window = DataEmitter() window.show() app.exec()
In this example:
- The textChanged signal of the QLineEdit widget is connected to the emit_data method.
- The custom signal data_signal is connected to the update_label method.
Example 2: Multi-Connection Signals
A signal can be connected to multiple slots.
class MultiSlotExample(QObject): signal = pyqtSignal() def slot_one(): print("Slot One Triggered") def slot_two(): print("Slot Two Triggered") example = MultiSlotExample() example.signal.connect(slot_one) example.signal.connect(slot_two) example.signal.emit()
Output:
Slot One Triggered Slot Two Triggered
Example 3: Using Decorators for Slots
from PyQt6.QtCore import pyqtSignal, pyqtSlot, QObject class DecoratorExample(QObject): signal = pyqtSignal(int) @pyqtSlot(int) def slot_function(self, value): print(f"Received value: {value}") example = DecoratorExample() example.signal.connect(example.slot_function) example.signal.emit(42)
Using the @pyqtSlot decorator optimizes signal-slot connections but is optional.
Summary
- Signals and slots enable flexible and decoupled event handling.
- Predefined signals (e.g., clicked) are easy to use.
- Custom signals add versatility to PyQt6 applications.
- Multiple slots can be connected to a single signal, and vice versa.