web-dev-qa-db-fra.com

Utilisation correcte de pyQt de emit () et pyqtSignal ()

Je lis une documentation sur PyQt5 pour trouver un mécanisme de signal-slot simple. Je me suis arrêté pour des raisons de conception.

Considérez le code suivant:

import sys
from PyQt5.QtCore import (Qt, pyqtSignal)
from PyQt5.QtWidgets import (QWidget, QLCDNumber, QSlider,
    QVBoxLayout, QApplication)


class Example(QWidget):

    def __init__(self):
        super().__init__()

        self.initUI()

    def printLabel(self, str):
        print(str)

    def logLabel(self, str):
        '''log to a file'''
        pass

    def initUI(self):

        lcd = QLCDNumber(self)
        sld = QSlider(Qt.Horizontal, self)

        vbox = QVBoxLayout()
        vbox.addWidget(lcd)
        vbox.addWidget(sld)

        self.setLayout(vbox)

        #redundant connections
        sld.valueChanged.connect(lcd.display)
        sld.valueChanged.connect(self.printLabel)
        sld.valueChanged.connect(self.logLabel)

        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('Signal & slot')
        self.show()


if __name__ == '__main__':

    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

Pour suivre les modifications apportées au curseur, j'imprime et enregistre simplement les modifications apportées. Ce que je n'aime pas dans le code, c'est que je dois appeler le slot sld.valueChanged Trois fois pour envoyer les mêmes informations à 3 slots différents.

Est-il possible de créer mon propre pyqtSignal qui envoie un entier à une fonction de slot unique. Et à son tour, la fonction slot émet-elle les modifications à apporter?

  • Peut-être que je ne comprends pas complètement le but de emit() parce qu'il n'y a pas de bons exemples de son but dans les PyQt Signal-Slot docs . Tout ce qui nous est donné est un exemple de la façon d'implémenter un emit sans paramètres.

Ce que je voudrais faire, c'est créer une fonction qui gère la fonction emit. Considérer ce qui suit:

import sys
from PyQt5.QtCore import (Qt, pyqtSignal)
from PyQt5.QtWidgets import (QWidget, QLCDNumber, QSlider,
    QVBoxLayout, QApplication)


class Example(QWidget):

    def __init__(self):
        super().__init__()

        #create signal
        self.val_Changed = pyqtSignal(int, name='valChanged')

        self.initUI()

    def initUI(self):

        lcd = QLCDNumber(self)
        sld = QSlider(Qt.Horizontal, self)

        vbox = QVBoxLayout()
        vbox.addWidget(lcd)
        vbox.addWidget(sld)

        self.setLayout(vbox)

        sld.val_Changed.connect(self.handle_LCD)
        self.val_Changed.emit()

        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('Signal & slot')
        self.show()

    def handle_LCD(self, text):
        '''log'''
        print(text)
        '''connect val_Changed to lcd.display'''

if __name__ == '__main__':

    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

Il y a évidemment de graves défauts de conception ici. Je ne peux pas m'intéresser à l'ordre des appels de fonction. Et je n'implémente pas correctement pyqtSignal. Je pense cependant que la formulation correcte des 3 points suivants m'aidera à produire une application appropriée:

  1. Pour un signal prédéfini: envoyez le signal à la fonction slot. La fente peut être réimplémentée pour utiliser les valeurs du signal.
  2. Produisez un objet pyqtSignal avec certains paramètres. Il n'est pas encore clair quel est le but de ces paramètres et comment ils diffèrent des paramètres "émettre".
  3. emit peut être réimplémenté pour envoyer des valeurs de signal spécifiques à la fonction slot. On ne sait pas encore pourquoi j'aurais besoin d'envoyer des valeurs différentes à partir de méthodes de signal existantes.

N'hésitez pas à modifier complètement le code de ce que j'essaie de faire parce que je n'ai pas encore compris si c'est dans le domaine du bon style.

19
Max

Vous pouvez définir votre propre slot (any python callable) et le connecter au signal, puis appeler les autres slots depuis ce slot).

class Example(QWidget):

    def __init__(self):
        super().__init__()
        self.initUI()

    def printLabel(self, str):
        print(str)

    def logLabel(self, str):
        '''log to a file'''
        pass

    @QtCore.pyqtSlot(int)
    def on_sld_valueChanged(self, value):
        self.lcd.display(value)
        self.printLabel(value)
        self.logLabel(value)

    def initUI(self):

        self.lcd = QLCDNumber(self)
        self.sld = QSlider(Qt.Horizontal, self)

        vbox = QVBoxLayout()
        vbox.addWidget(self.lcd)
        vbox.addWidget(self.sld)

        self.setLayout(vbox)
        self.sld.valueChanged.connect(self.on_sld_valueChanged)


        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('Signal & slot')

De plus, si vous souhaitez définir vos propres signaux, ils doivent être définis comme des variables de classe

class Example(QWidget):
    my_signal = pyqtSignal(int)

Les arguments de pyqtSignal définissent les types d'objets qui seront emit 'd sur ce signal, donc dans ce cas, vous pourriez faire

self.my_signal.emit(1)

emit peut être réimplémenté pour envoyer des valeurs de signal spécifiques à la fonction slot. On ne sait pas encore pourquoi j'aurais besoin d'envoyer des valeurs différentes à partir de méthodes de signal existantes.

Vous ne devriez généralement pas émettre les signaux intégrés. Vous ne devez émettre que des signaux que vous définissez. Lors de la définition d'un signal, vous pouvez définir différentes signatures avec différents types et les emplacements peuvent choisir à quelle signature ils veulent se connecter. Par exemple, vous pouvez le faire

my_signal = pyqtSignal([int], [str])

Cela définira un signal avec deux signatures différentes, et un slot pourrait se connecter à l'un ou l'autre

@pyqtSlot(int)
def on_my_signal_int(self, value):
    assert isinstance(value, int)

@pyqtSlot(str)
def on_my_signal_str(self, value):
    assert isinstance(value, str)

En pratique, je surcharge rarement les signatures de signaux. Je créerais normalement deux signaux séparés avec des signatures différentes plutôt que de surcharger le même signal. Mais il existe et est pris en charge dans PyQt car Qt a des signaux qui sont surchargés de cette façon (par exemple. QComboBox.currentIndexChanged )

26
Brendan Abel