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
| # -*- coding: utf-8 -*-
import sys
import time
from PyQt5 import (QtWidgets, QtCore)
#############################################################################
class Operationlongue(QtCore.QThread):
# crée deux nouveaux signaux pour communiquer avec le graphique
info = QtCore.pyqtSignal(int) # signal pour informer d'une progression
fini = QtCore.pyqtSignal(bool, list) # signal pour informer de la fin du thread
#========================================================================
def __init__(self, parent=None):
super().__init__(parent)
# initialise un drapeau pour signaler une demande d'arrêt anticipé
self.stop = False
#========================================================================
def run(self):
"""seule 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) # tempo pour ralentir la boucle
self.info.emit(i) # envoi du signal de progression d'exécution
# envoi du signal de fin du thread:
# self.stop dira si la fin est normale (False) ou pas (True)
# et [1,2,3] n'est qu'un exemple de données envoyées par le thread
self.fini.emit(self.stop, [1,2,3])
#========================================================================
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("Arrêt", self)
self.arret.clicked.connect(self.stopthread)
# barre de progression
self.pbarre = QtWidgets.QProgressBar(self)
self.pbarre.setAlignment(QtCore.Qt.AlignHCenter)
self.pbarre.setRange(0, 100)
self.pbarre.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.pbarre, 2, 0)
self.setLayout(posit)
# initialise la variable d'instance de classe du thread
self.operationlongue = None
#========================================================================
@QtCore.pyqtSlot(bool)
def lancement(self, ok=False):
"""lance l'opération longue dans le thread
"""
if self.operationlongue==None or not self.operationlongue.isRunning():
# initialise la barre de progression
self.pbarre.reset()
self.pbarre.setRange(0, 100)
self.pbarre.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.finduthread)
# 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 émise par le thread
"""
self.pbarre.setValue(i)
#========================================================================
@QtCore.pyqtSlot(bool)
def stopthread(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 finduthread(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.pbarre.setValue(100)
QtWidgets.QMessageBox.information(self,
"Opération longue",
"Fin normale!")
# récupération des infos transmises par signal à la fin du thread
print("Infos données par le thread:", liste)
# désactive les liens
self.operationlongue.info.disconnect()
self.operationlongue.fini.disconnect()
# signale quil n'y a plus de thread actif
self.operationlongue = None
#========================================================================
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():
# désactive les liens
self.operationlongue.info.disconnect()
self.operationlongue.fini.disconnect()
# et arrête brutalement le thread
self.operationlongue.terminate()
# accepte la fermeture de la fenêtre
event.accept()
#############################################################################
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
fen = Fenetre()
fen.show()
sys.exit(app.exec_()) |
Partager