Les signaux et les slots

Qt introduit le principe de la communication à partir de signaux et de slots. Cela permet de gérer des relations entre des objets avec un couplage faible. De plus, Qt gère de manière transparente la communication directe ou à travers une file de messages (message queue) qui peut servir pour la communication inter threads lorsque des objets ont été créés dans des threads séparés.

Les signaux

Tous les objets qui héritent de QObject peuvent émettre des signaux. Un signal est représenté par une instance de la classe Signal. Un signal possède une méthode emit() qui prend en paramètre une valeur qui peut être transmise avec le signal. La valeur peut être n’importe quel type Python mais ce dernier doit être précisé lors de la création du signal.

from PySide2.QtCore import QObject, Signal

class Alarme(QObject):

    sonnerie = Signal()
    message = Signal(str)

    def declencher(self):
        self.sonnerie.emit()
        self.message.emit("L'alarme se déclenche")

Dans l’exemple ci-dessus, on déclare deux signaux possibles pour la classe Alarme. La méthode declencher émet les deux signaux.

Les slots

Les slots sont des méthodes qui pourront être connectées à un signal de manière à être appelées lors de l’émission du signal. Un slot doit accepter en paramètre le même type de données que celui émis par un signal. On utilise le décorateur @Slot pour déclarer un slot. On précise au décorateur le type du paramètre.

from PySide2.QtCore import Slot

class Sirene:

    @Slot()
    def sonner(self):
        print("faire du bruit")
from PySide2.QtCore import Slot

class Messagerie:

    @Slot(str)
    def envoyer(self, message):
        print(f"envoyer le message '{message}'")

Connecter les signaux et les slots

L’intérêt principal des signaux et des slots est de permettre un couplage faible entre les classes en connectant a posteriori les signaux à des slots grâce à la méthode connect qui prend en paramètre le slot à connecter.

alarme = Alarme()
sirene = Sirene()
messagerie = Messagerie()

alarme.sonnerie.connect(sirene.sonner)
alarme.message.connect(messagerie.envoyer)

alarme.declencher()
# Affiche
# faire du bruit
# envoyer le message 'L'alarme se déclenche'

Note

Un signal peut émettre plusieurs valeurs et, symétriquement, un slot peut accepter plusieurs paramètres. Dans ce cas, il faut déclarer le type de chaque paramètre.