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 :

Comment avoir une boucle qui modifie les widgets ? [QtGui]


Sujet :

PyQt Python

  1. #1
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2022
    Messages
    2
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 21
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2022
    Messages : 2
    Points : 3
    Points
    3
    Par défaut Comment avoir une boucle qui modifie les widgets ?
    Bonjour tout le monde !

    Depuis peu je suis entrain de développer un Chat IRC pour un projet perso.
    Mon problème est le suivant, je n'arrive pas à modifier le widget pour qu'il m'affiche le message reçu du serveur.


    Comment je procède ?

    Tout d'abord j'ai créer une fonction ("listener()") qui à pour rôle de récupérer les informations du serveur. Tout ce passe très bien côté console, les messages je les récupèrent bien et j'arrive à les afficher côté console.
    Mais ensuite pour mettre à jour le widget pour qu'il puissent m'afficher ces messages, impossible.

    Nom : image_2022-11-08_183652717.png
Affichages : 288
Taille : 10,1 Ko
    Nom : 08335736bb1c3ad5a012b7d5984e8769.png
Affichages : 300
Taille : 15,4 Ko

    1. Première idée

    Au début je me suis dit qu'il suffit juste de créer un fonction qui se charge de modifier l'affichage et lui aussi je le met dans un thread comme ceci:

    Nom : image_2022-11-08_182950382.png
Affichages : 281
Taille : 12,8 Ko
    Nom : image_2022-11-08_183201609.png
Affichages : 316
Taille : 24,2 Ko

    Mais là, rien, la fenêtre s'ouvre puis se ferme, je reçois les premières informations du serveur, mais comme la fenêtre crash le programme s'arrête.

    Nom : Sans titre.png
Affichages : 279
Taille : 12,9 Ko

    2. Deuxième idée

    Là je me suis dit, que si ça fonctionne pas c'est parce que la boucle de récupération de message s'active trop souvent, alors je lui ai ajouter un time.sleep(2) (un délai d'attente de 2s)

    Nom : image.png
Affichages : 304
Taille : 241,8 Ko

    Ici comme vous pouvez le constater ça affiche les premiers messages, puis plus rien et au bout d'un certain temps ça crash encore, il est écrit (finished with exit code -1073741819 (0xC0000005))

    3. Troisième idée

    Là je me suis dit bon pyqt5 met à disposition qtcore qui lui à une classe Thread, avec un tuto je suis arrivé à là:

    Nom : image_2022-11-08_185726246.png
Affichages : 277
Taille : 27,1 Ko
    Nom : image_2022-11-08_185910324.png
Affichages : 278
Taille : 26,3 Ko

    Ici crash aussi, mais cette fois ci il est écrit (finished with exit code -1073740791 (0xC0000409))

    4. Quatrième idée

    Arrivé à là je deviens fou xD, bon je me dit que pyqt5 a sûrement une boucle d'évènement sans quoi il serait impossible de cliquer sur le boutons ou autre, mais je ne suis pas aller plus loin car je n'ai pas trouvé de moyen de
    l'implémenter

    Voici le code ici:
    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
    from PyQt5.QtWidgets import *
    from PyQt5.QtCore import *
    from PyQt5 import uic
    from server import Server
    import threading
    import socket
    import time
     
     
    #VARIABLES GLOBALES
    NICKNAME = "le_nom_ici"
    HOST = "irc.root-me.org"
    PORT = 6667
    TEXTERECIVE = ""
     
    SERVER = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    SERVER.connect((HOST, PORT))
     
    cmdNICK = f"NICK {NICKNAME}\r\n"
    cmdPASS = f"PASS NADA\r\n"
    cmdUSER = f"USER {NICKNAME} {NICKNAME} {NICKNAME} : _{NICKNAME}_\r\n"
     
    data = [cmdNICK, cmdPASS, cmdUSER]
    for element in data:
        SERVER.send(element.encode())
     
    def listener():
        global TEXTERECIVE
        while True:
            text = SERVER.recv(2040)
            TEXTERECIVE = text.decode("UTF-8")
            print(TEXTERECIVE)
     
    def sendServer(data):
        data += "\r\n"
        SERVER.send(data.encode())
     
    class MainGui(QMainWindow):
        def __init__(self):
            super(MainGui, self).__init__()
            uic.loadUi("GUI/main.ui", self)
     
            self.text = ''
     
            self.pushButton.clicked.connect(lambda: self.sendMessage(self.lineEdit.text()))
            self.lineEdit.returnPressed.connect(lambda: self.sendMessage(self.lineEdit.text()))
     
            self.show()
     
        def sendMessage(self, msg):
            if msg != '':
                sendServer(msg)
                self.text = self.plainTextEdit.toPlainText()
     
                self.text += f"[{NICKNAME}]: {msg}\r\n"
     
                self.plainTextEdit.setPlainText(self.text)
                self.lineEdit.clear()
     
        def afficheRecivedMessage(self):
            self.reciver_thread = MessageReciverThread()
            self.reciver_thread.start()
     
    class MessageReciverThread(QThread):
        def run(self):
            while True:
                if TEXTERECIVE != "":
                    self.text = self.plainTextEdit.toPlainText()
                    self.text += f"{TEXTERECIVE}\r\n"
                    self.plainTextEdit.setPlainText(self.text)
    def main():
        application = QApplication([])
        main_window = MainGui()
     
        main_window.afficheRecivedMessage()
     
        listener_thread = threading.Thread(target=listener, daemon=True)
        #reciver_trhead = threading.Thread(target=main_window.afficheRecivedMessage, daemon=True)
     
        listener_thread.start()
        #reciver_trhead.start()
     
        application.exec_()
     
    if __name__ == '__main__':
        main()

    Je suis à court d'idées, je vous remercie d'avoir lu jusqu'ici, je suis désolé si la solution est triviale mais là je sèche sévèrement xD, désolé d'avance pour les fautes x(.

  2. #2
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 464
    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 464
    Points : 9 254
    Points
    9 254
    Billets dans le blog
    6
    Par défaut
    Bonjour

    La boucle de traitement des évènements est lancée dans ton code par la ligne "application.exec_()". Une fois que le graphique a fait ce qu'il doit faire, il attend qu'on lui demande quelque chose: un évènement (clavier, souris, etc...).

    Mais ce que tu cherches, c'est comment un thread peut-il faire parvenir des infos au graphique, en obligeant celui-ci à les exploiter immédiatement. C'est ce qu'on utilise, par exemple, pour mettre à jour une barre de progression.

    Mais il y a quelque chose qu'il ne faut pas oublier: le thread ne doit pas, lui-même, toucher directement au graphique. Sinon, plantage aléatoire.

    La solution, c'est:
    - créer un nouveau signal au sein du thread (QtCore.pyqtSignal(...))
    - permettre au thread d'envoyer un message au graphique porté par ce signal (.emit()), qui sera traité par la boucle de traitement des évènements du graphique
    - faire que le graphique s'attende à recevoir un tel signal et message, et à lancer une méthode particulière à chaque fois

    Pour émettre un tel signal, il faut utiliser QThread et non threading.

    Voilà un petit code de test en PyQt5 qui montre la mise à jour d'une barre de progression.

    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
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    #!/usr/bin/python3
    # -*- coding: utf-8 -*-
     
    import sys
    import time
    from PyQt5 import (QtWidgets, QtCore)
     
    #############################################################################
    class Operationlongue(QtCore.QThread):
     
        # création des nouveaux signaux
        info = QtCore.pyqtSignal(int) # signal pour informer d'une progression
        fini = QtCore.pyqtSignal(bool, list) # signal pour la fin du thread
     
        #========================================================================
        def __init__(self, parent=None):
            super().__init__(parent)
     
            self.stop = False # drapeau pour exécuter une demande d'arrêt
     
        #========================================================================
        def run(self):
            """partie qui s'exécute en tâche de fond
            """
            for i in range(0, 101):
                if self.stop:
                    break # arrêt anticipé demandé
                time.sleep(0.05)
                self.info.emit(i) # envoi du signal de progression d'exécution
            # fin du thread
            self.fini.emit(self.stop, [1,2,3]) # envoi du signal de fin d'exécution
     
        #========================================================================
        def arreter(self):
            """pour arrêter avant la fin normale d'exécution du thread
            """
            self.stop = True
     
    #############################################################################
    class Fenetre(QtWidgets.QWidget):
     
        #========================================================================
        def __init__(self, parent=None):
            super().__init__(parent)
     
            # bouton de lancement du thread
            self.depart = QtWidgets.QPushButton("Départ", self)
            self.depart.clicked.connect(self.lancement)
     
            # bouton d'arrêt anticipé du thread
            self.arret = QtWidgets.QPushButton(u"Arrêt", self)
            self.arret.clicked.connect(self.arreter)
     
            # barre de progression
            self.barre = QtWidgets.QProgressBar(self)
            self.barre.setRange(0, 100)
            self.barre.setValue(0)
     
            # positionne les widgets dans la fenêtre
            posit = QtWidgets.QGridLayout()
            posit.addWidget(self.depart, 0, 0)
            posit.addWidget(self.arret, 1, 0)
            posit.addWidget(self.barre, 2, 0)
            self.setLayout(posit)
     
            # initialisation variable d'instance de classe
            self.operationlongue = None
     
        #========================================================================
        @QtCore.pyqtSlot(bool)
        def lancement(self, ok=False):
            """lancement de l'opération longue dans le thread
            """
            if self.operationlongue==None or not self.operationlongue.isRunning():
                # initialise la barre de progression
                self.barre.reset()
                self.barre.setRange(0, 100)
                self.barre.setValue(0)
                # initialise l'opération longue dans le thread
                self.operationlongue = Operationlongue()
                # prépare la réception du signal de progression
                self.operationlongue.info.connect(self.progression)
                # prépare la réception du signal de fin
                self.operationlongue.fini.connect(self.stop)
                # lance le thread (mais ne l'attend pas avec .join!!!)
                self.operationlongue.start()
     
        #========================================================================
        @QtCore.pyqtSlot(int)
        def progression(self, i):
            """lancé à chaque réception d'info de progression émis par le thread
            """
            self.barre.setValue(i)
            QtCore.QCoreApplication.processEvents() # force le rafraichissement
     
        #========================================================================
        @QtCore.pyqtSlot(bool)
        def arreter(self, ok=False):
            """pour arrêter avant la fin
            """
            if self.operationlongue!=None and self.operationlongue.isRunning():
                self.operationlongue.arreter()
     
        #========================================================================
        @QtCore.pyqtSlot(bool, list)
        def stop(self, fin_anormale=False, liste=()):
            """Lancé quand le thread se termine
            """
            if fin_anormale:
                # fin anticipée demandée
                QtWidgets.QMessageBox.information(self,
                    "Opération longue",
                    "Arrêt demandé avant la fin!")
            else:
                # fin normale
                self.barre.setValue(100)
                QtWidgets.QMessageBox.information(self,
                    "Opération longue",
                    "Fin normale!")
                # récupération des infos transmises par signal à la fin du thread
                print(liste)
     
        #========================================================================
        def closeEvent(self, event):
            """lancé à la fermeture de la fenêtre quelqu'en soit la méthode
            """
            # si le thread est en cours d'eécution, on l'arrête (brutalement!)
            if self.operationlongue!=None and self.operationlongue.isRunning():
                self.operationlongue.terminate()
            # et on accepte la fermeture de la fenêtre dans tous les cas
            event.accept()
     
    #############################################################################
    if __name__ == "__main__":
        app = QtWidgets.QApplication(sys.argv)
        fen = Fenetre()
        fen.setAttribute(QtCore.Qt.WA_DeleteOnClose)
        fen.show()
        sys.exit(app.exec_())
    [Edit] voir la doc concernant la gestion des signaux de PyQt5: https://www.riverbankcomputing.com/s...als_slots.html
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  3. #3
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 690
    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 690
    Points : 30 986
    Points
    30 986
    Billets dans le blog
    1
    Par défaut
    Salut
    Citation Envoyé par tyrtamos Voir le message
    Voilà un petit code de test en PyQt5 qui montre la mise à jour d'une barre de progression.
    Super ton code, il m'a bien aidé à comprendre les thread

    Toutefois je me demande si on aurait pas avantage à créer le thread dans le init du widget plutôt qu'au lancement du travail.
    Ensuite (et surtout) on peut éviter l'attribut "stop" en utilisant la méthode terminate() d'un thread dédiée justement à l'arrêter. Ca me semble plus propre que passer par un flag interne.
    Et si cette méthode est appelée, le thread sait qu'il s'agit d'un arrêt forcé et peut remonter cette info au widget.
    Et ainsi on n'embête pas le travail en lui demandant de vérifier cette valeur "stop"...

    Exemple
    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
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    #!/usr/bin/env python3
    # coding: utf-8
     
    import sys
    import time
    from PyQt5.QtCore import *
    from PyQt5.QtWidgets import *
     
    # L'objet de travail dans un thread
    class cWork(QThread):
    	sigInfo=pyqtSignal(int)					# Signal information travail
    	sigTerminated=pyqtSignal(bool)			# Signal travail terminé
     
    	# Constructeur
    	def __init__(self, bornes, *args, **kwargs):
    		# Appel méthode objet hérité
    		super().__init__(*args, **kwargs)
     
    		# Les bornes min/max
    		self.__bornes=bornes
    	# ___init__()
     
    	# Lancement du travail
    	def run(self):
    		# Le travail sera pour l'exemple une simple boucle
    		for i in range(*self.__bornes):
    			# A intervalle régulier, le thread informe de son avancement
    			self.sigInfo[int].emit(i)
     
    			# On simule que le travail prenne du temps
    			time.sleep(0.05)
    		# for
     
    		# Le travail s'est terminé sans interruption
    		self.sigTerminated[bool].emit(True)
    	# run()
     
    	# Arrêt du thread (méthode surchargée)
    	def terminate(self):
    		print("terminé")
    		# Appel méthode objet hérité
    		super().terminate()
     
    		# La doc précise qu'il vaut mieux rajouter ensuite un wait()
    		self.wait()
     
    		# Puisque l'arrêt a été forcé, le travail n'est pas terminé
    		self.sigTerminated[bool].emit(False)
    	# terminate()
    # class cWork()
     
    # La fenêtre d'affichage de la barre de progression
    class myWidget(QWidget):
    	def __init__(self, bornes=(0, 100), *args, **kwargs):
    		# Appel méthode objet hérité
    		super().__init__(*args, **kwargs)
     
    		# Les bornes du travail
    		self.__bornes=bornes
     
    		# Création thread
    		self.__work=cWork(self.__bornes)
     
    		# On connecte la progression du thread à un slot dédié
    		self.__work.sigInfo[int].connect(self.__slotProgress)
     
    		# On connecte la fin du thread à un slot dédié
    		self.__work.sigTerminated[bool].connect(self.__slotTerminated)
     
    		# Boutons départ et arrêt
    		self.__startBtn=QPushButton("Départ", parent=self, clicked=self.__slotStart)
    		self.__stopBtn=QPushButton("Arrêt", parent=self, clicked=self.__slotStop)
     
    		# Barre de progression
    		self.__progress=QProgressBar(parent=self)
    		self.__progress.setAlignment(Qt.AlignHCenter)
    		self.__progress.setRange(0, 100)
     
    		# Layout de positionnement
    		mainLayout=QVBoxLayout(self)
    		mainLayout.addWidget(self.__startBtn, stretch=0)
    		mainLayout.addWidget(self.__stopBtn, stretch=0)
    		mainLayout.addStretch(1)
    		mainLayout.addWidget(self.__progress, stretch=0)
     
    		# Affichage fenêtre
    		self.show()
    	# __init__()
     
    	# Le slot de démarrage du thread
            @pyqtSlot(bool)
    	def __slotStart(self, _):
    		# Si le thread est déjà en route, il ne redémarre pas
    		if self.__work.isRunning(): return
     
    		# Initialise la barre de progression
    		self.__progress.reset()
     
    		# Lance le thread (mais ne l'attend pas avec .join!!!)
    		self.__work.start()
    	# __slotStart()
     
    	# Le slot d'arrêt du thread
            @pyqtSlot(bool)
    	def __slotStop(self, _):
    		# Si le thread est déjà arrêté, il ne s'arrête pas deux fois
    		if not self.__work.isRunning(): return
     
    		# Thread arrêté de force
    		self.__work.terminate()
    	# __slotStop()
     
    	# Met à jour la barre de progression
            @pyqtSlot(int)
    	def __slotProgress(self, i):
    		self.__progress.setValue(
    			i * self.__progress.maximum() // (self.__bornes[1] - self.__bornes[0] - 1)
    		)
    	# __slotProgress()
     
    	# Lorsque le travail se termine
            @pyqtSlot(bool)
    	def __slotTerminated(self, terminated):
    		QMessageBox.information(
    			self,
    			"Opération longue",
    			"Fin normale" if terminated else "Arrêt demandé avant la fin!",
    		)
    	# __slotTerminated()
     
    	# Evènement fermeture fenêtre (méthode surchargée)
    	def closeEvent(self, event):
    		# Si le thread est actif
    		if self.__work.isRunning():
    			# Arrêt thread
    			self.__work.terminate()
     
    			# Désactive les liens (pas certain que ce soit vraiment nécessaire mais...)
    			self.__work.sigInfo[int].disconnect()
    			self.__work.sigTerminated[bool].disconnect()
    		# if
     
    		# Appel méthode objet hérité (comportement par défaut)
    		super().closeEvent(event)
    	# closeEvent()
    # class myWidget
     
    # Dans le cas d'une exécution directe du script
    if __name__ == "__main__":
    	app=QApplication(sys.argv)
    	fen=myWidget((0, 200))
    	sys.exit(app.exec_())
    # if

    Et euh... plus besoin de "u" devant les strings sous P3
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  4. #4
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 464
    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 464
    Points : 9 254
    Points
    9 254
    Billets dans le blog
    6
    Par défaut
    Bonjour Sve@r

    Citation Envoyé par Sve@r Voir le message
    Toutefois je me demande si on aurait pas avantage à créer le thread dans le init du widget plutôt qu'au lancement du travail.
    Comme on demande au thread une tâche ponctuelle avec un début et une fin, je trouve ça plus logique comme je fais. Et on peut relancer le thread (nouvelle instance) pour faire un autre calcul. Et à l'arrêt du thread, je peux déconnecter les signaux du thread (ce qui n'a pas été fait dans le code test mais que je fais d'habitude). Mais rien n'empêche de faire autrement, y compris lancer le thread à l'initiation du programme et le garder jusqu'au bout, à condition de coder le thread pour qu'il puisse recevoir un ordre de travail et renvoyer le résultat sans pour autant se terminer.

    Citation Envoyé par Sve@r Voir le message
    Ensuite (et surtout) on peut éviter l'attribut "stop" en utilisant la méthode terminate() d'un thread dédiée justement à l'arrêter. Ca me semble plus propre que passer par un flag interne.
    Et si cette méthode est appelée, le thread sait qu'il s'agit d'un arrêt forcé et peut remonter cette info au widget.
    Et ainsi on n'embête pas le travail en lui demandant de vérifier cette valeur "stop"...
    Ce n'est pas mon avis. ".terminate()" est un arrêt brutal et sauvage qui fait que, après lui, aucune donnée du thread n'est plus valable (c'est dans la doc). Je ne l'utilise donc que pour des cas ou je n'attends plus rien du thread, à l'arrêt du programme par exemple. Alors qu'avec un drapeau, on peut renvoyer une info (.emit(...)) disant qu'un arrêt demandé a été fait par l'utilisateur.

    Citation Envoyé par Sve@r Voir le message
    Et euh... plus besoin de "u" devant les strings sous P3
    Et oui, c'était un code Python 2 modernisé (incomplètement)
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  5. #5
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 690
    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 690
    Points : 30 986
    Points
    30 986
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par tyrtamos Voir le message
    Mais rien n'empêche de faire autrement, y compris lancer le thread à l'initiation du programme et le garder jusqu'au bout, à condition de coder le thread pour qu'il puisse recevoir un ordre de travail et renvoyer le résultat sans pour autant se terminer.
    Ok, c'est juste un souci de point de vue. Ton objet Fenetre est envisagé comme pouvant être utilisé une fois mais générer plusieurs travaux, donc fatalement il doit créer le thread quand on lui demande "lance un job" tandis que le mien est dédié à un seul travail (quitte à être instancié n fois si on veut n travaux) donc je peux de mon côté lui faire créer le thread à son instanciation.

    Citation Envoyé par tyrtamos Voir le message
    Ce n'est pas mon avis. ".terminate()" est un arrêt brutal et sauvage qui fait que, après lui, aucune donnée du thread n'est plus valable (c'est dans la doc).
    Ah ouais, t'as raison "Warning: This function is dangerous and its use is discouraged. The thread can be terminated at any point in its code path. Threads can be terminated while modifying data.". Zut !!!

    C'est quand-même bizarre, on t'offre une fonction pour faire un truc et on te dit "nan nan, faut pas l'utiliser pour ce truc, démerde toi autrement". Et que penses-tu de passer alors par quit() ??? Je veux dire que c'est dommage de devoir créer un flag, il doit bien y avoir un moyen de dire au thread "arrête-toi proprement et préviens ton utilisateur"...

    [edit]Bon ben le quit() ne fonctionne pas. Ca arrête bien le thread mais ensuite impossible de le faire redémarrer (ou alors en créer un différent à chaque lancement du travail)... Je crois bien qu'on ne peut pas faire autrement que passer par un flag.

    Bon, ma version (mais elle me plaît moins que la précédente même si elle est plus propre... enfin je m'y habituerai)
    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
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    #!/usr/bin/env python3
    # coding: utf-8
     
    import sys
    import time
    from PyQt5.QtCore import *
    from PyQt5.QtWidgets import *
     
    # L'objet de travail dans un thread
    class cWork(QThread):
    	sigInfo=pyqtSignal(int)					# Signal information travail
    	sigTerminated=pyqtSignal(bool)			# Signal travail terminé
     
    	# Constructeur
    	def __init__(self, bornes, *args, **kwargs):
    		# Appel méthode objet hérité
    		super().__init__(*args, **kwargs)
     
    		# Les bornes min/max
    		self.__bornes=bornes
     
    		# Etat en cours/arrêté
    		self.__job=False
    	# ___init__()
     
    	# Lancement du travail
    	def run(self):
    		# Lancement du travail
    		self.__job=True
     
    		# Le travail sera pour l'exemple une simple boucle
    		for i in range(*self.__bornes):
    			# Si le thread est arrêté, on arrête le travail
    			if not self.__job: break
     
    			# On simule que le travail prenne du temps
    			time.sleep(0.05)
     
    			# A intervalle régulier, le thread informe de son avancement
    			self.sigInfo[int].emit(i)
    		# for
     
    		# Message travail terminé (avec interruption ou pas)
    		self.sigTerminated[bool].emit(self.__job)
     
    		# Quoi qu'il arrive, ici le travail est réellement terminé
    		self.__job=False
    	# run()
     
    	# Arrêt du thread
    	def stop(self): self.__job=False
    # class cWork()
     
    # La fenêtre d'affichage de la barre de progression
    class myWidget(QWidget):
    	def __init__(self, bornes=(0, 100), *args, **kwargs):
    		# Appel méthode objet hérité
    		super().__init__(*args, **kwargs)
     
    		# Les bornes du travail
    		self.__bornes=bornes
     
    		# Création thread
    		self.__work=cWork(self.__bornes)
     
    		# On connecte la progression du thread à un slot dédié
    		self.__work.sigInfo[int].connect(self.__slotProgress)
     
    		# On connecte la fin du thread à un slot dédié
    		self.__work.sigTerminated[bool].connect(self.__slotTerminated)
     
    		# Boutons départ et arrêt
    		self.__startBtn=QPushButton("Départ", parent=self, pressed=self.__slotStart)
    		self.__stopBtn=QPushButton("Arrêt", parent=self, pressed=self.__slotStop)
     
    		# Barre de progression
    		self.__progress=QProgressBar(parent=self)
    		self.__progress.setAlignment(Qt.AlignHCenter)
    		self.__progress.setRange(0, 100)
     
    		# Layout de positionnement
    		mainLayout=QVBoxLayout(self)
    		mainLayout.addWidget(self.__startBtn, stretch=0)
    		mainLayout.addWidget(self.__stopBtn, stretch=0)
    		mainLayout.addStretch(1)
    		mainLayout.addWidget(self.__progress, stretch=0)
     
    		# Affichage fenêtre
    		self.show()
    	# __init__()
     
    	# Le slot de démarrage du thread
            @pyqtSlot()
    	def __slotStart(self):
    		# Si le thread est déjà en route, il ne redémarre pas
    		if self.__work.isRunning(): return
     
    		# Initialise la barre de progression
    		self.__progress.reset()
     
    		# Lance le thread (mais ne l'attend pas avec .join!!!)
    		self.__work.start()
    	# __slotStart()
     
    	# Le slot d'arrêt du thread
            @pyqtSlot()
    	def __slotStop(self):
    		# Si le thread est déjà arrêté, il ne s'arrête pas deux fois
    		if not self.__work.isRunning(): return
     
    		# Thread arrêté
    		self.__work.stop()
    	# __slotStop()
     
    	# Met à jour la barre de progression
            @pyqtSlot(int)
    	def __slotProgress(self, i):
    		self.__progress.setValue(
    			i * self.__progress.maximum() // (self.__bornes[1] - self.__bornes[0] - 1)
    		)
     
    		# On force le rafraichissement (utile ???)
    		QCoreApplication.processEvents()
    	# __slotProgress()
     
    	# Lorsque le travail se termine
            @pyqtSlot(bool)
    	def __slotTerminated(self, terminated):
    		QMessageBox.information(
    			self,
    			"Opération longue",
    			"Fin normale" if terminated else "Arrêt demandé avant la fin!",
    		)
    	# __slotTerminated()
     
    	# Evènement fermeture fenêtre (méthode surchargée)
    	def closeEvent(self, event):
    		# Si le thread est actif
    		if self.__work.isRunning():
    			# Arrêt thread
    			self.__work.stop()
    			self.__work.terminate()
    			self.__work.wait()
     
    			# Message final
    			self.__slotTerminated(terminated=False)
    		# if
     
    		# Désactive les liens (pas certain que ce soit vraiment nécessaire mais...)
    		self.__work.sigInfo[int].disconnect()
    		self.__work.sigTerminated[bool].disconnect()
     
    		# Appel méthode objet hérité (comportement par défaut)
    		super().closeEvent(event)
    	# closeEvent()
    # class myWidget
     
    # Dans le cas d'une exécution directe du script
    if __name__ == "__main__":
    	app=QApplication(sys.argv)
    	fen=myWidget((0, 200))
    	sys.exit(app.exec_())
    # if
    J'ai rajouté un terminate() dans le closeEvent() mais je ne sais pas trop si c'est nécessaire ou pas...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  6. #6
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2022
    Messages
    2
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 21
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2022
    Messages : 2
    Points : 3
    Points
    3
    Par défaut Résolution
    Citation Envoyé par tyrtamos Voir le message
    Bonjour

    La boucle de traitement des évènements est lancée dans ton code par la ligne "application.exec_()". Une fois que le graphique a fait ce qu'il doit faire, il attend qu'on lui demande quelque chose: un évènement (clavier, souris, etc...).

    Mais ce que tu cherches, c'est comment un thread peut-il faire parvenir des infos au graphique, en obligeant celui-ci à les exploiter immédiatement. C'est ce qu'on utilise, par exemple, pour mettre à jour une barre de progression.

    Mais il y a quelque chose qu'il ne faut pas oublier: le thread ne doit pas, lui-même, toucher directement au graphique. Sinon, plantage aléatoire.

    La solution, c'est:
    - créer un nouveau signal au sein du thread (QtCore.pyqtSignal(...))
    - permettre au thread d'envoyer un message au graphique porté par ce signal (.emit()), qui sera traité par la boucle de traitement des évènements du graphique
    - faire que le graphique s'attende à recevoir un tel signal et message, et à lancer une méthode particulière à chaque fois

    Pour émettre un tel signal, il faut utiliser QThread et non threading.

    Voilà un petit code de test en PyQt5 qui montre la mise à jour d'une barre de progression.

    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
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    #!/usr/bin/python3
    # -*- coding: utf-8 -*-
     
    import sys
    import time
    from PyQt5 import (QtWidgets, QtCore)
     
    #############################################################################
    class Operationlongue(QtCore.QThread):
     
        # création des nouveaux signaux
        info = QtCore.pyqtSignal(int) # signal pour informer d'une progression
        fini = QtCore.pyqtSignal(bool, list) # signal pour la fin du thread
     
        #========================================================================
        def __init__(self, parent=None):
            super().__init__(parent)
     
            self.stop = False # drapeau pour exécuter une demande d'arrêt
     
        #========================================================================
        def run(self):
            """partie qui s'exécute en tâche de fond
            """
            for i in range(0, 101):
                if self.stop:
                    break # arrêt anticipé demandé
                time.sleep(0.05)
                self.info.emit(i) # envoi du signal de progression d'exécution
            # fin du thread
            self.fini.emit(self.stop, [1,2,3]) # envoi du signal de fin d'exécution
     
        #========================================================================
        def arreter(self):
            """pour arrêter avant la fin normale d'exécution du thread
            """
            self.stop = True
     
    #############################################################################
    class Fenetre(QtWidgets.QWidget):
     
        #========================================================================
        def __init__(self, parent=None):
            super().__init__(parent)
     
            # bouton de lancement du thread
            self.depart = QtWidgets.QPushButton("Départ", self)
            self.depart.clicked.connect(self.lancement)
     
            # bouton d'arrêt anticipé du thread
            self.arret = QtWidgets.QPushButton(u"Arrêt", self)
            self.arret.clicked.connect(self.arreter)
     
            # barre de progression
            self.barre = QtWidgets.QProgressBar(self)
            self.barre.setRange(0, 100)
            self.barre.setValue(0)
     
            # positionne les widgets dans la fenêtre
            posit = QtWidgets.QGridLayout()
            posit.addWidget(self.depart, 0, 0)
            posit.addWidget(self.arret, 1, 0)
            posit.addWidget(self.barre, 2, 0)
            self.setLayout(posit)
     
            # initialisation variable d'instance de classe
            self.operationlongue = None
     
        #========================================================================
        @QtCore.pyqtSlot(bool)
        def lancement(self, ok=False):
            """lancement de l'opération longue dans le thread
            """
            if self.operationlongue==None or not self.operationlongue.isRunning():
                # initialise la barre de progression
                self.barre.reset()
                self.barre.setRange(0, 100)
                self.barre.setValue(0)
                # initialise l'opération longue dans le thread
                self.operationlongue = Operationlongue()
                # prépare la réception du signal de progression
                self.operationlongue.info.connect(self.progression)
                # prépare la réception du signal de fin
                self.operationlongue.fini.connect(self.stop)
                # lance le thread (mais ne l'attend pas avec .join!!!)
                self.operationlongue.start()
     
        #========================================================================
        @QtCore.pyqtSlot(int)
        def progression(self, i):
            """lancé à chaque réception d'info de progression émis par le thread
            """
            self.barre.setValue(i)
            QtCore.QCoreApplication.processEvents() # force le rafraichissement
     
        #========================================================================
        @QtCore.pyqtSlot(bool)
        def arreter(self, ok=False):
            """pour arrêter avant la fin
            """
            if self.operationlongue!=None and self.operationlongue.isRunning():
                self.operationlongue.arreter()
     
        #========================================================================
        @QtCore.pyqtSlot(bool, list)
        def stop(self, fin_anormale=False, liste=()):
            """Lancé quand le thread se termine
            """
            if fin_anormale:
                # fin anticipée demandée
                QtWidgets.QMessageBox.information(self,
                    "Opération longue",
                    "Arrêt demandé avant la fin!")
            else:
                # fin normale
                self.barre.setValue(100)
                QtWidgets.QMessageBox.information(self,
                    "Opération longue",
                    "Fin normale!")
                # récupération des infos transmises par signal à la fin du thread
                print(liste)
     
        #========================================================================
        def closeEvent(self, event):
            """lancé à la fermeture de la fenêtre quelqu'en soit la méthode
            """
            # si le thread est en cours d'eécution, on l'arrête (brutalement!)
            if self.operationlongue!=None and self.operationlongue.isRunning():
                self.operationlongue.terminate()
            # et on accepte la fermeture de la fenêtre dans tous les cas
            event.accept()
     
    #############################################################################
    if __name__ == "__main__":
        app = QtWidgets.QApplication(sys.argv)
        fen = Fenetre()
        fen.setAttribute(QtCore.Qt.WA_DeleteOnClose)
        fen.show()
        sys.exit(app.exec_())
    [Edit] voir la doc concernant la gestion des signaux de PyQt5: https://www.riverbankcomputing.com/s...als_slots.html
    Énorme merci ! Ton code m'a grandement aidé, pour faire simple, dans ma méthode run() j'ai mis le code qui me permet de recevoir les informations du serveur, et dans la classe de ma fenêtre, j'ai créé une fonction qui s'occupe de gérer le QThread et de récupérer l'information de si oui ou non j'ai reçu un signal, et quand je reçoit le signal "j'appelle" ma fonction d'affichage !

    Merci à vous de m'avoir accordé votre temps et merci de vos réponses !

  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 690
    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 690
    Points : 30 986
    Points
    30 986
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Swidenn Voir le message
    et dans la classe de ma fenêtre, j'ai créé une fonction qui s'occupe de gérer le QThread et de récupérer l'information de si oui ou non j'ai reçu un signal, et quand je reçoit le signal "j'appelle" ma fonction d'affichage !
    Je me demande pourquoi tu fais ça dans un thread, pourquoi ce n'est pas la fenêtre qui récupère directement les messages du serveur pour les afficher...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  8. #8
    Expert éminent

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 300
    Points : 6 780
    Points
    6 780
    Par défaut
    Citation Envoyé par tyrtamos Voir le message

    Pour émettre un tel signal, il faut utiliser QThread et non threading.
    Non, non, ça fonctionne identiquement avec un thread python.

  9. #9
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 464
    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 464
    Points : 9 254
    Points
    9 254
    Billets dans le blog
    6
    Par défaut
    Bonjour VinsS

    Citation Envoyé par VinsS Voir le message
    Non, non, ça fonctionne identiquement avec un thread python.
    A ma connaissance, mais peut-être ça a changé récemment, on ne peut émettre un signal dans une classe thread que dans 2 cas:
    - la classe hérite de QThread
    - la classe a un héritage multiple "threading.Thread + QtCore.QObject", car c'est QObject et ses descendants qui donnent cette capacité d'émission de signal.

    Je viens de faire un essai rapide dans mon code test. Si la classe thread, au lieu d'hériter de QtCore.QThread, hérite de threading.Thread, cela déclenche l'erreur:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    ERREUR CRITIQUE:
    Traceback (most recent call last):
      File "D:\pythondev\Pydev\projetpython\PyQt5\QThread\modele\test06.py", line 86, in lancement
        self.operationlongue.info.connect(self.progression)
    TypeError: Operationlongue cannot be converted to PyQt5.QtCore.QObject in this context
    Mais si l'héritage devient multiple: "class Operationlongue(threading.Thread, QtCore.QObject):", le programme fonctionne!

    As-tu un exemple qui montre que ta proposition marche?
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  10. #10
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 690
    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 690
    Points : 30 986
    Points
    30 986
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par tyrtamos Voir le message
    Mais si l'héritage devient multiple: "class Operationlongue(threading.Thread, QtCore.QObject):", le programme fonctionne!
    Euh... pas chez-moi

    Si j'ai bien compris; on définit la classe ainsi

    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class Operationlongue(threading.Thread, QtCore.QObject):
     
    	# création des nouveaux signaux
    	info = QtCore.pyqtSignal(int) # signal pour informer d'une progression
    	fini = QtCore.pyqtSignal(bool, list) # signal pour la fin du thread
     
    	#========================================================================
    	def __init__(self, parent=None):
    		super().__init__(parent)
     
    		self.stop = False # drapeau pour exécuter une demande d'arrêt
    ... (tout le reste à l'identique)

    Mais au résultat...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Traceback (most recent call last):
      File "/tmp/c.py", line 83, in lancement
        self.operationlongue.info.connect(self.progression)
    RuntimeError: super-class __init__() of type Operationlongue was never called
    Et si on inverse l'héritage (class Operationlongue(QtCore.QObject, threading.Thread)), alors il se lance bien, la barre de progression "progresse" (donc le signal passe bien), mais dès qu'on clique sur "stop" => AttributeError: 'Operationlongue' object has no attribute 'isRunning'.
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  11. #11
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 464
    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 464
    Points : 9 254
    Points
    9 254
    Billets dans le blog
    6
    Par défaut
    @ Sve@r

    Pour ta 1ère erreur: comme il s'agit d'un héritage multiple, il faut initialiser les 2 ancêtres!

    Pour ta 2ème erreur: isRunning est spécifique à QThread et n'existe pas dans threading.Thread. Mais il y a l'équivalent!
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  12. #12
    Expert éminent

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 300
    Points : 6 780
    Points
    6 780
    Par défaut
    Oui, oui ces classes héritent de QObject mais uniquement de cela.

    Ex:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    class ArteTV(QObject):
        """Define the arte TV Guide server handler.
     
        """
        parsingFinished = pyqtSignal(int)
        mergingFinished = pyqtSignal(str, str)
        def __init__(self, core):
            super().__init__()

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

Discussions similaires

  1. Réponses: 10
    Dernier message: 13/08/2007, 16h12
  2. Réponses: 10
    Dernier message: 28/07/2007, 15h53
  3. Comment avoir une appli qui se passe d'install d'un client oracle?
    Par korntex5 dans le forum Bases de données
    Réponses: 3
    Dernier message: 26/06/2007, 14h57
  4. Réponses: 2
    Dernier message: 06/04/2007, 13h31
  5. Réponses: 1
    Dernier message: 03/05/2006, 10h49

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