aboutsummaryrefslogtreecommitdiffstats
path: root/sources/pyside6/doc/tutorials/basictutorial/signals_and_slots.rst
diff options
context:
space:
mode:
Diffstat (limited to 'sources/pyside6/doc/tutorials/basictutorial/signals_and_slots.rst')
-rw-r--r--sources/pyside6/doc/tutorials/basictutorial/signals_and_slots.rst214
1 files changed, 122 insertions, 92 deletions
diff --git a/sources/pyside6/doc/tutorials/basictutorial/signals_and_slots.rst b/sources/pyside6/doc/tutorials/basictutorial/signals_and_slots.rst
index 470b4ab70..0bfd9e276 100644
--- a/sources/pyside6/doc/tutorials/basictutorial/signals_and_slots.rst
+++ b/sources/pyside6/doc/tutorials/basictutorial/signals_and_slots.rst
@@ -43,101 +43,104 @@ a signal directly to another signal. (This will emit the second signal
immediately whenever the first is emitted.)
Qt's widgets have many predefined signals and slots. For example,
-`QAbstractButton` (base class of buttons in Qt) has a `clicked()`
-signal and `QLineEdit` (single line input field) has a slot named
-'clear()`. So, a text input field with a button to clear the text
-could be implemented by placing a `QToolButton` to the right of the
-`QLineEdit` and connecting its `clicked()` signal to the slot
-'clear()`. This is done using the `connect()` method of the signal:
+``QAbstractButton`` (base class of buttons in Qt) has a ``clicked()``
+signal and ``QLineEdit`` (single line input field) has a slot named
+``clear()``. So, a text input field with a button to clear the text
+could be implemented by placing a ``QToolButton`` to the right of the
+``QLineEdit`` and connecting its ``clicked()`` signal to the slot
+``clear()``. This is done using the ``connect()`` method of the signal:
- .. code-block:: python
+.. code-block:: python
- button = QToolButton()
- line_edit = QLineEdit()
- button.clicked.connect(line_edit.clear)
+ button = QToolButton()
+ line_edit = QLineEdit()
+ button.clicked.connect(line_edit.clear)
-`connect()` returns a `QMetaObject.Connection` object, which can be
-used with the `disconnect()` method to sever the connection.
+``connect()`` returns a ``QMetaObject.Connection`` object, which can be
+used with the ``disconnect()`` method to sever the connection.
Signals can also be connected to free functions:
- .. code-block:: python
+.. code-block:: python
- import sys
- from PySide6.QtWidgets import QApplication, QPushButton
+ import sys
+ from PySide6.QtWidgets import QApplication, QPushButton
- def function():
- print("The 'function' has been called!")
+ def function():
+ print("The 'function' has been called!")
- app = QApplication()
- button = QPushButton("Call function")
- button.clicked.connect(func)
- button.show()
- sys.exit(app.exec())
+ app = QApplication()
+ button = QPushButton("Call function")
+ button.clicked.connect(function)
+ button.show()
+ sys.exit(app.exec())
Connections can be spelled out in code or, for widget forms,
designed in the
`Signal-Slot Editor <https://doc.qt.io/qt-6/designer-connection-mode.html>`_
-of Qt Designer.
+of *Qt Widgets Designer*.
The Signal Class
----------------
When writing classes in Python, signals are declared as class level
variables of the class ``QtCore.Signal()``. A QWidget-based button
-that emits a `clicked()` signal could look as
+that emits a ``clicked()`` signal could look as
follows:
- .. code-block:: python
+.. code-block:: python
- from PySide6.QtCore import Qt, Signal
- from PySide6.QtWidgets import QWidget
+ from PySide6.QtCore import Qt, Signal
+ from PySide6.QtWidgets import QWidget
- class Button(QWidget):
+ class Button(QWidget):
- clicked = Signal(Qt.MouseButton)
+ clicked = Signal(Qt.MouseButton)
- ...
+ ...
- def mousePressEvent(self, event):
- self.clicked.emit(event.button())
+ def mousePressEvent(self, event):
+ self.clicked.emit(event.button())
The constructor of ``Signal`` takes a tuple or a list of Python types
and C types:
- .. code-block:: python
+.. code-block:: python
- signal1 = Signal(int) # Python types
- signal2 = Signal(QUrl) # Qt Types
- signal3 = Signal(int, str, int) # more than one type
- signal4 = Signal((float,), (QDate,)) # optional types
+ signal1 = Signal(int) # Python types
+ signal2 = Signal(QUrl) # Qt Types
+ signal3 = Signal(int, str, int) # more than one type
+ signal4 = Signal((float,), (QDate,)) # optional types
In addition to that, it can receive also a named argument ``name`` that defines
the signal name. If nothing is passed, the new signal will have the same name
as the variable that it is being assigned to.
- .. code-block:: python
+.. code-block:: python
- # TODO
- signal5 = Signal(int, name='rangeChanged')
- # ...
- rangeChanged.emit(...)
+ # TODO
+ signal5 = Signal(int, name='rangeChanged')
+ # ...
+ rangeChanged.emit(...)
Another useful option of ``Signal`` is the arguments name,
useful for QML applications to refer to the emitted values by name:
- .. code-block:: python
+.. code-block:: python
- sumResult = Signal(int, arguments=['sum'])
+ sumResult = Signal(int, arguments=['sum'])
- .. code-block:: javascript
+.. code-block:: javascript
- Connections {
- target: ...
- function onSumResult(sum) {
- // do something with 'sum'
- }
+ Connections {
+ target: ...
+ function onSumResult(sum) {
+ // do something with 'sum'
+ }
+
+
+.. _slot-decorator:
The Slot Class
--------------
@@ -146,11 +149,11 @@ Slots in QObject-derived classes should be indicated by the decorator
``@QtCore.Slot()``. Again, to define a signature just pass the types
similar to the ``QtCore.Signal()`` class.
- .. code-block:: python
+.. code-block:: python
- @Slot(str)
- def slot_function(self, s):
- ...
+ @Slot(str)
+ def slot_function(self, s):
+ ...
``Slot()`` also accepts a ``name`` and a ``result`` keyword.
@@ -159,6 +162,19 @@ Python type. The ``name`` keyword behaves the same way as in ``Signal()``. If
nothing is passed as name then the new slot will have the same name as the
function that is being decorated.
+We recommend marking all methods used by signal connections with a
+``@QtCore.Slot()`` decorator. Not doing causes run-time overhead due to the
+method being added to the ``QMetaObject`` when creating the connection. This is
+particularly important for ``QObject`` classes registered with QML, where
+missing decorators can introduce bugs.
+
+Missing decorators can be diagnosed by setting activating warnings of the
+logging category ``qt.pyside.libpyside``; for example by setting the
+environment variable:
+
+.. code-block:: bash
+
+ export QT_LOGGING_RULES="qt.pyside.libpyside.warning=true"
.. _overloading-signals-and-slots:
@@ -172,62 +188,76 @@ In Qt 6, signals have distinct names for different types.
The following example uses two handlers for a Signal and a Slot to showcase
the different functionality.
- .. code-block:: python
+.. code-block:: python
- import sys
- from PySide6.QtWidgets import QApplication, QPushButton
- from PySide6.QtCore import QObject, Signal, Slot
+ import sys
+ from PySide6.QtWidgets import QApplication, QPushButton
+ from PySide6.QtCore import QObject, Signal, Slot
- class Communicate(QObject):
- # create two new signals on the fly: one will handle
- # int type, the other will handle strings
- speak = Signal((int,), (str,))
+ class Communicate(QObject):
+ # create two new signals on the fly: one will handle
+ # int type, the other will handle strings
+ speak = Signal((int,), (str,))
- def __init__(self, parent=None):
- super().__init__(self, parent)
+ def __init__(self, parent=None):
+ super().__init__(parent)
- self.speak[int].connect(self.say_something)
- self.speak[str].connect(self.say_something)
+ self.speak[int].connect(self.say_something)
+ self.speak[str].connect(self.say_something)
- # define a new slot that receives a C 'int' or a 'str'
- # and has 'say_something' as its name
- @Slot(int)
- @Slot(str)
- def say_something(self, arg):
- if isinstance(arg, int):
- print("This is a number:", arg)
- elif isinstance(arg, str):
- print("This is a string:", arg)
+ # define a new slot that receives a C 'int' or a 'str'
+ # and has 'say_something' as its name
+ @Slot(int)
+ @Slot(str)
+ def say_something(self, arg):
+ if isinstance(arg, int):
+ print("This is a number:", arg)
+ elif isinstance(arg, str):
+ print("This is a string:", arg)
+
+ if __name__ == "__main__":
+ app = QApplication(sys.argv)
+ someone = Communicate()
- if __name__ == "__main__":
- app = QApplication(sys.argv)
- someone = Communicate()
+ # emit 'speak' signal with different arguments.
+ # we have to specify the str as int is the default
+ someone.speak.emit(10)
+ someone.speak[str].emit("Hello everybody!")
- # emit 'speak' signal with different arguments.
- # we have to specify the str as int is the default
- someone.speak.emit(10)
- someone.speak[str].emit("Hello everybody!")
+.. _signals-and-slots-strings:
Specifying Signals and Slots by Method Signature Strings
--------------------------------------------------------
Signals and slots can also be specified as C++ method signature
-strings passed through the `SIGNAL()` and/or `SLOT()` functions:
+strings passed through the ``SIGNAL()`` and/or ``SLOT()`` functions:
+
+.. code-block:: python
+
+ from PySide6.QtCore import SIGNAL, SLOT
+
+ button.connect(SIGNAL("clicked(Qt::MouseButton)"),
+ action_handler, SLOT("action1(Qt::MouseButton)"))
+
+This is not normally recommended; it is only needed
+for a few cases where signals are only accessible via ``QMetaObject``
+(``QAxObject``, ``QAxWidget``, ``QDBusInterface`` or ``QWizardPage::registerField()``):
- .. code-block:: python
+.. code-block:: python
- from PySide6.QtCore import SIGNAL, SLOT
+ wizard.registerField("text", line_edit, "text",
+ SIGNAL("textChanged(QString)"))
- button.connect(SIGNAL("clicked(Qt::MouseButton)"),
- action_handler, SLOT("action1(Qt::MouseButton)"))
+The signature strings can be found by querying ``QMetaMethod.methodSignature()``
+when introspecting ``QMetaObject``:
-This is not recommended for connecting signals, it is mostly
-used to specify signals for methods like `QWizardPage::registerField()`:
+.. code-block:: python
- .. code-block:: python
+ mo = widget.metaObject()
+ for m in range(mo.methodOffset(), mo.methodCount()):
+ print(mo.method(m).methodSignature())
- wizard.registerField("text", line_edit, "text",
- SIGNAL("textChanged(QString)"))
+Slots should be decorated using :ref:`@Slot <slot-decorator>`.