@ fred1599
J'ai réussi! Mais ce n'est pas plus simple, au contraire...
La solution avec le "self.obj = QtCore.QObject()" ne marche pas, parce qu'on ne sait pas comment la raccorder avec les signaux, et on ne peut donc ni se connecter, ni émettre.
Cela donne par exemple comme erreur critique:
Alors, j'ai créé une nouvelle classe héritant de QtCore.Object, et comportant tout ce qui appartient à la gestion des signaux. Cette classe "Emission" est appelée par le thread, ce qui permet au graphique de l'appeler aussi par l'intermédiaire du thread pour la connexion des signaux avec les méthodes.Code:TypeError: Operationlongue cannot be converted to PyQt5.QtCore.QObject in this context
Voici le code avec thereading.Thread, mais avec héritage simple:
Je rappelle la solution avec threading.Thread mais avec héritage multiple:Code:
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 #!/usr/bin/python3 # -*- coding: utf-8 -*- import sys import time import threading from PyQt5 import (QtWidgets, QtCore) ############################################################################# class Emission(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): super().__init__() #======================================================================== def emetinfo(self, valint): self.info.emit(valint) #======================================================================== def emetfini(self, ok, liste): self.fini.emit(ok, liste) ############################################################################# class Operationlongue(threading.Thread): #======================================================================== def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.obj = Emission() # classe utilisée pour l'émission des signaux 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.obj.emetinfo(i) # envoi du signal de progression d'exécution # fin du thread self.obj.emetfini(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.is_alive(): # 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.obj.info.connect(self.progression) # prépare la réception du signal de fin self.operationlongue.obj.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.is_alive(): self.operationlongue.arreter() #======================================================================== @QtCore.pyqtSlot(bool, list) def stop(self, fin_anormale=False, liste=()): """Lancé quand le thread se termine La liste simule le retour d'une information de fin """ 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.is_alive(): 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_())
Et je rappelle enfin la solution avec QtCore.QThread et héritage simple, que je recommande chaleureusement: :DCode:
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 #!/usr/bin/python3 # -*- coding: utf-8 -*- import sys import time import threading from PyQt5 import (QtWidgets, QtCore) ############################################################################# 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, *args, **kwargs): threading.Thread.__init__(self, *args, **kwargs) QtCore.QObject.__init__(self) 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.is_alive(): # 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.is_alive(): 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.is_alive(): 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_())
Bien entendu, ces 3 solutions fonctionnent! Elles donnent une fenêtre comme ça:Code:
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, *args, **kwargs): super().__init__(*args, **kwargs) 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_())
Pièce jointe 628928
Ouf... :D