IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

PyQt Python Discussion :

PySide 6 - Signaux et Slots entre plusieurs Classes


Sujet :

PyQt Python

  1. #1
    Membre actif Avatar de FadeToBlack
    Homme Profil pro
    ...
    Inscrit en
    Août 2010
    Messages
    314
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : ...
    Secteur : Associations - ONG

    Informations forums :
    Inscription : Août 2010
    Messages : 314
    Points : 204
    Points
    204
    Par défaut PySide 6 - Signaux et Slots entre plusieurs Classes
    Bonjour à tous,

    J'ai une petite question concernant les signaux et les slots. j'ai compris leurs fonctionnement mais j'ai un petit problème.

    Considérant que j'ai trop classes : A, B, C
    - A instancie B qui instancie C
    Est-il possible d'émettre un signal à partir de C et qu'il soit récupéré dans A, sans passer par B.

    Par extension, est-il possible de créer des connexion via les signaux et slots entre deux classes qui n'ont pas de relations ?

    Je sais mes questions sont peut-être un peu C.... , mais je n'arrive pas à trouver la réponse.

    Bonne journée à tous.

  2. #2
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 480
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 480
    Points : 9 277
    Points
    9 277
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    Je ne travaille pas avec PySide6, mais d'après ce que je comprends de Qt:

    - la classe qui émet un signal (prédéfini ou non) ne sait pas d'avance qui va le récupérer

    - la classe qui veut récupérer ce signal doit donner pour ça:
    --- l'origine du signal
    --- le nom du signal
    --- la méthode à exécuter à la réception

    En conséquence, le traitement du signal est forcément extérieur aux 2 classes (traitement des évènements?). Donc, rien ne s'oppose à ce que n'importe quelle classe puisse recevoir un signal de n'importe quelle autre classe, même s'il existe une relation entre elles. Mais il faut que la classe qui reçoit puisse citer la variable d'instance de la classe qui émet (=l'origine du signal).

    Essaie!

  3. #3
    Membre actif Avatar de FadeToBlack
    Homme Profil pro
    ...
    Inscrit en
    Août 2010
    Messages
    314
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : ...
    Secteur : Associations - ONG

    Informations forums :
    Inscription : Août 2010
    Messages : 314
    Points : 204
    Points
    204
    Par défaut
    Bonsoir Tyrtamos,

    Encore une fois tu viens à mon secours. ..... Quand je dis que je suis sur PySide6, c'est effectivement le cas. Mais j'aurais pu considérer être sur Pyqt5 ou Pyside 2. Les différences, pour ce que je domine QT, sont assez minimes.

    Quoiqu'il en soit tu me confirmes que je puisse faire quelques chose du genre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
     
     
     class_A():
        def madef(self) :
            B = class2()
     
     class2():
        def madef_B(self) :
            C = class3()
     
    class3():
        mon_signal = Signal(obj)
        def madef_C(self) :
            mon_signal.emit(mon_obj)
     
     
    et de retour dans A()
     
     class A():
        def madef(self) :
            B = class2()
     
        def madef_slot(self) :
            C.mon_signal.connect(etc....)

    Tu penses que cela peut fonctionner ? Cela serait logique mais.....
    JE vais voir.


    Bonne soirée

  4. #4
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 351
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 351
    Points : 36 875
    Points
    36 875
    Par défaut
    Salut,

    Citation Envoyé par FadeToBlack Voir le message
    Tu penses que cela peut fonctionner ? Cela serait logique mais.....
    C'est le connect qui établit la relation entre l'instance du C et l'instance du A.
    L'instance du C est stocké dans un attribut de l'instance du B crée par A.

    Si a la création du B on passe l'instance de A, l'initialisation de B peut très bien connecter un signal de l'instance de C avec un slot de l'instance de A.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class A(QObject):
           ....
           def __init__(self,....):
                ...
                self.b = B(self)
                ...
     
    class B(QObject):
           ....
           def __init__(self, a, ....):
                ...
                self.c = C()
                self.connect(self.c,..., a,...)
    Bien sûr, on peut faire autrement mais quand on fait le connect, il faudra toujours accéder à l'instance de A et à l'instance de C à connecter.

    Tout çà pour dire que signal et slot n'est pas une mécanique de publish/suscribe où ceux qui émettent ignorent ce qui vont consommer (grâce à une médiation intermédiaire). C'est plutôt une mécanique genre pattern observateur où l'émetteur à une référence les objets à qui expédier le message et s'assure de la notification.

    - W

  5. #5
    Membre actif Avatar de FadeToBlack
    Homme Profil pro
    ...
    Inscrit en
    Août 2010
    Messages
    314
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : ...
    Secteur : Associations - ONG

    Informations forums :
    Inscription : Août 2010
    Messages : 314
    Points : 204
    Points
    204
    Par défaut
    Bonjour à vous deux.

    @wiztricks, j'ai essayé ton idée, et j'arrive à un bon résultat. Voici le code en action

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
     
    import sys
     
    from PySide6.QtCore import Signal, Slot
    from PySide6.QtWidgets import QApplication, QPushButton, QWidget, QLineEdit, QVBoxLayout
     
     
    class main_window(QWidget):
        def __init__(self):
            super(main_window, self).__init__()
     
            self.ini_ui()
     
        def ini_ui(self):
            self.setWindowTitle("Fenêtre principale")
            self.resize(400, 100)
            self.btn = QPushButton("clique")
            self.btn.clicked.connect(self.appel_deuxieme)
            self.txt = QLineEdit()
            self.txt_from3 = QLineEdit()
     
            vb = QVBoxLayout(self)
            vb.addWidget(self.txt)
            vb.addWidget(self.txt_from3)
            vb.addWidget(self.btn)
     
            self.setLayout(vb)
     
            self.show()
     
        def appel_deuxieme(self):
            print(self.txt.text())
            self.sec = deuxieme(self)
            troisieme.signal3.connect(self.msg_de_troisieme)
     
        @Slot(str)
        def msg_de_troisieme(self, msg):
            self.txt.setText(msg)
     
     
    class deuxieme(QWidget):
        def __init__(self, a):
            self.inst_main = a
            super(deuxieme, self).__init__()
            self.ini_ui()
     
        def ini_ui(self):
            self.setWindowTitle("Seconde fenêtre")
            self.resize(400, 100)
     
            self.btn2 = QPushButton("clique")
            self.btn2.clicked.connect(self.appel_troisieme)
            self.txt_2 = QLineEdit()
            self.txt_from3 = QLineEdit()
     
            vb_2 = QVBoxLayout()
            vb_2.addWidget(self.txt_2)
            vb_2.addWidget(self.txt_from3)
            vb_2.addWidget(self.btn2)
     
            self.setLayout(vb_2)
            self.show()
     
        def appel_troisieme(self):
            print(self.txt_2.text())
            self.trois = troisieme()
            self.trois.signal3.connect(self.msg_de_troisieme)
     
     
        @Slot(str)
        def msg_de_troisieme(self, msg):
            self.txt_from3.setText(msg)
            self.inst_main.txt_from3.setText(msg)
     
     
    class troisieme(QWidget):
        signal3 = Signal(str)
     
        def __init__(self):
            super(troisieme, self).__init__()
            self.ini_ui()
     
        def ini_ui(self):
            self.setWindowTitle("troisième fenêtre")
            self.resize(400, 100)
     
            self.btn3 = QPushButton("clique")
            self.btn3.clicked.connect(self.retour_vers_main)
            self.txt_3 = QLineEdit()
     
            vb_3 = QVBoxLayout()
            vb_3.addWidget(self.txt_3)
            vb_3.addWidget(self.btn3)
     
            self.setLayout(vb_3)
            self.show()
     
        def retour_vers_main(self):
            print('toto')
            self.signal3.emit("bonjour de la  troisieme")
     
     
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        mainw = main_window()
        sys.exit(app.exec())
    Comme vous pouvez le voir, cela fonctionne puisque le "clique" sur la troisième fenêtre ajoute un message dans la fenêtre principale. Néanmoins, le process a été défini dans le code de la classe "deuxieme", à laquelle j'ai passé une instance de "principale"?. (cf ligne 33).


    Par contre, je n'arrive pas à mettre du code dans la "principale" pour se connecter directement au signal émit par "troisieme".

    Avec quelque chose de concrêt, ce sera sans doute plus parlant.

    Merci de votre aide

  6. #6
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 351
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 351
    Points : 36 875
    Points
    36 875
    Par défaut
    Citation Envoyé par FadeToBlack Voir le message
    Par contre, je n'arrive pas à mettre du code dans la "principale" pour se connecter directement au signal émit par "troisieme".
    Où que vous essayez de faire le connect, il faut avoir accès aux instances.

    Et dans le bout de code qu'il y a autour de la ligne33:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
        def appel_deuxieme(self):
            print(self.txt.text())
            self.sec = deuxieme(self)
            troisieme.signal3.connect(self.msg_de_troisieme)
    troisième est la classe et non l'instance de troisième.

    Et comme cette instance n'est pas créée à l'initialisation de deuxième, impossible de la récupérer à ce moment là.

    - W

  7. #7
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 721
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 721
    Points : 31 044
    Points
    31 044
    Billets dans le blog
    1
    Par défaut
    Salut
    Citation Envoyé par FadeToBlack Voir le message
    Par contre, je n'arrive pas à mettre du code dans la "principale" pour se connecter directement au signal émit par "troisieme".
    Il faut que la principale connaisse la 3° pour qu'il puisse dire "connecte 3.signal à principale.slot"
    Or c'est la 2° qui crée la 3° donc il faut que la principale puisse dire à la 2° "donne-moi la 3°".

    Un exemple schématisé
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    class principale():
    	def __init__(self):
    		self.seconde=seconde()
    		self.seconde.troisieme.signal.connect(self.slotAction)
     
    	self.slotAction(self):
    		print("action")
     
    class seconde():
    	def __init__(self):
    		self.troisieme=troisieme()
     
    class troisieme():
    	def __init__(self):
    		...
    		signal.emit()

    Et un exemple PyQt5 (que tu ne devrais pas avoir de mal à porter sous PySide...)
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    #!/usr/bin/env python3
    # coding: utf-8
     
    from PyQt5.QtCore import *
    from PyQt5.QtGui import *
    from PyQt5.QtWidgets import *
    import sys
     
    class myAppli(QApplication):
    	def __init__(self, *args, **kwargs):
    		super().__init__(*args, **kwargs)
    		self.mainWid=widPrincipal()
    	# __init__()
     
    	def exec_(self):
    		self.mainWid.show()
    		return super().exec_()
    	# exec_()
    # class myAppli
     
    # La widget principale
    class widPrincipal(QWidget):
    	def __init__(self, *args, **kwargs):
    		super().__init__(*args, **kwargs)
     
    		# Une zone de texte
    		self.text=QLineEdit(parent=self)
    		self.text.setReadOnly(True)
     
    		# La w1 (qui va crééer une w2)...
    		self.w1=widget1(parent=self)
    		self.w1.w2.sigAction[str].connect(self.slotAction)
     
    		mainLayout=QVBoxLayout(self)
    		mainLayout.addWidget(self.text, stretch=0)
    		mainLayout.addWidget(self.w1, stretch=0)
    		mainLayout.addWidget(self.w1.w2, stretch=0)
    	# __init__()
     
            @pyqtSlot(str)
    	def slotAction(self, s):
    		self.text.setText("".join(reversed(s)))
    # class widPrincipal
     
    # La sous-widget 1 (qui crée la w2)
    class widget1(QWidget):
    	def __init__(self, *args, **kwargs):
    		super().__init__(*args, **kwargs)
    		self.w2=widget2(parent=self)
     
    		# Une zone de texte
    		text=QLineEdit("sous-widget1", parent=self)
    		text.setReadOnly(True)
     
    		mainLayout=QVBoxLayout(self)
    		mainLayout.addWidget(text, stretch=0)
    	# __init__()
    # class widget1
     
    # La sous-widget 2 (qui fait saisir un texte et qui l'envoie par un signal)
    class widget2(QWidget):
    	sigAction=pyqtSignal(str)
     
    	def __init__(self, *args, **kwargs):
    		super().__init__(*args, **kwargs)
     
    		# Une zone de texte
    		self.text=QLineEdit(parent=self, textEdited=self.slotText)
    		layout1=QHBoxLayout()
    		layout1.addWidget(QLabel("Entrez un texte ici :", parent=self), stretch=0)
    		layout1.addWidget(self.text, stretch=1)
     
    		mainLayout=QVBoxLayout(self)
    		mainLayout.addLayout(layout1, stretch=0)
    	# __init__()
     
    	def slotText(self, s):
    		self.sigAction[str].emit(s)
    # class widget2
     
    if __name__ == "__main__":
    	sys.exit(myAppli(sys.argv).exec_())

  8. #8
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 480
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 480
    Points : 9 277
    Points
    9 277
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    J'ai repris le 1er code et je l'ai complété pour qu'il fonctionne. Il ne devrait pas être compliqué de le mettre sous PySide6:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    from PyQt5 import QtCore 
     
    class Class_A(QtCore.QObject):
     
        def madef(self) :
            self.B = Class2()
            self.C = self.B.madef_B()
            self.C.mon_signal.connect(self.recup)
     
        def demandeinfo(self):
            self.C.madef_C()
     
        def recup(self, info):
            print(info) 
     
    class Class2(QtCore.QObject):
     
        def madef_B(self) :
            self.C = Class3()
            self.C.madef_C()
            return self.C
     
    class Class3(QtCore.QObject):
     
        mon_signal = QtCore.pyqtSignal(str)
     
        def madef_C(self) :
            self.mon_signal.emit("toto")
     
     
    class_A = Class_A()
    class_A.madef()
     
    class_A.demandeinfo() # => affiche "toto"
    On voit bien que pour que ça marche, la classe qui reçoit le signal (Classe_A) doit connaître l'instance de la classe qui l'émet (Classe_C).

  9. #9
    Membre actif Avatar de FadeToBlack
    Homme Profil pro
    ...
    Inscrit en
    Août 2010
    Messages
    314
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : ...
    Secteur : Associations - ONG

    Informations forums :
    Inscription : Août 2010
    Messages : 314
    Points : 204
    Points
    204
    Par défaut
    Merci à tous,

    Vos propositions m'ont bien aidé.

    Ce que je voulais tient la route maintenant.

    Encore une fois merci.

    A la prochaine fois pour une autre question.

    Bonne journée

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [QtCore] Signaux et slots entre deux classes dans deux fichiers
    Par FadeToBlack dans le forum PyQt
    Réponses: 6
    Dernier message: 14/02/2018, 08h35
  2. Signaux et slot entre plusieurs objets
    Par sepiropht dans le forum Qt
    Réponses: 9
    Dernier message: 26/06/2014, 11h58
  3. objet partagé entre plusieurs classes
    Par grinder59 dans le forum C#
    Réponses: 16
    Dernier message: 13/05/2010, 16h07
  4. VC++ echange de donnees entre plusieurs Classe
    Par PePedu78 dans le forum Visual C++
    Réponses: 2
    Dernier message: 18/02/2008, 19h32
  5. Erreur signaaux et slots entre 2 classes
    Par Shaika-Dzari dans le forum Qt
    Réponses: 4
    Dernier message: 20/04/2007, 13h27

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo