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
| #!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
from PyQt5 import (QtWidgets, QtCore)
# pour la simulation d'une tâche longue
from time import sleep
##############################################################################
class Iterateur(object):
def __init__(self, deb, fin=None, pas=None):
if pas==None:
if fin==None:
# 1 seul paramètre
self.deb, self.fin, self.pas = 0, deb, 1
else:
# 2 paramètres
self.deb, self.fin, self.pas = deb, fin, 1
else:
# 3 paramètres
self.deb, self.fin, self.pas = deb, fin, pas
self.cpt = self.deb # initialisation du compteur
def __iter__(self):
return self
def __next__(self): # => "next" pour Python2 et "__next__" pour Python3
if self.cpt >= self.fin:
raise StopIteration
k = self.cpt
self.cpt += self.pas # incrementation du compteur pour le prochain appel
return k
#############################################################################
class Monthread(QtCore.QThread):
# création d'un nouveau signal pour info du % d'avancement
progduthread = QtCore.pyqtSignal(float)
# création d'un nouveau signal pour info de la fin du thread
finduthread = QtCore.pyqtSignal(str)
#========================================================================
def __init__(self, parent=None):
super().__init__(parent)
#========================================================================
def run(self):
# nb d'itération prévue
nmax = 100
# lancement d'une tâche longue
for i in Iterateur(nmax):
# simule une tâche de calcul longue
sleep(0.1)
# envoi de l'info de progression au graphique
self.progduthread.emit((i+1)/100)
# signale que le thread est terminé
self.finduthread.emit("Fin de l'action")
#############################################################################
class Fenetre(QtWidgets.QWidget):
#========================================================================
def __init__(self, parent=None):
super().__init__(parent)
self.resize(300, 200)
# bouton qui exécute la méthode action
self.bouton = QtWidgets.QPushButton("début", self)
self.bouton.clicked.connect(self.action)
# position du bouton dans la fenêtre
posit = QtWidgets.QGridLayout()
posit.addWidget(self.bouton, 0, 0)
self.setLayout(posit)
# création des variables définies plus tard
self.monthread = None
self.prog = None
#========================================================================
def action(self):
"""méthode lancée par le bouton pour démarrer ou stopper une
opération longue dans un thread
"""
if self.monthread == None or not self.monthread.isRunning():
# => démarrage de l'action dans le thread
# création du QProgressDialog
self.prog = QtWidgets.QProgressDialog("En cours...", "Annuler", 0, 100, self)
self.prog.setWindowTitle("Action")
# branchement du bouton "annuler" à la méthode 'stopaction'
self.prog.canceled.connect(self.stopaction)
# affichage de la fenêtre de progression
self.prog.show()
# lancement du thread avec son opération
self.monthread = Monthread()
# se préparer à recevoir le % d'avancement
self.monthread.progduthread.connect(self.progression)
# se préparer à recevoir le signal de fin du thread
self.monthread.finduthread.connect(self.finaction)
# démarrer le thread
self.monthread.start()
# surtout pas de "self.monthread.join()" ici!!!
# changement du texte du bouton
self.bouton.setText("Stop")
else:
# => arrêt du thread avant la fin, demandé par le bouton "Stop"
self.stopaction()
#========================================================================
def progression(self, pourc):
"""mise à jour de la barre de progression
"""
self.prog.setValue(pourc * 100)
if pourc >= 100:
self.prog.reset()
#========================================================================
def stopaction(self):
"""méthode lancée par le bouton "annuler" de la fenêtre de progression
"""
# débranchement des liens
self.monthread.progduthread.disconnect()
self.monthread.finduthread.disconnect()
# arrêt brutal du thread
self.monthread.terminate()
# arrêt de la fenêtre de progression
self.prog.reset()
# retour au texte initial du bouton
self.bouton.setText("Début")
#========================================================================
def finaction(self, msg):
"""méthode lancée à la fin normale du thread
"""
# arrêt de la fenêtre de progression
self.prog.reset()
# retour au texte initial du bouton
self.bouton.setText("Début")
# affichage du message de fin
QtWidgets.QMessageBox.information(self,
"Information",
msg)
#############################################################################
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
fen = Fenetre()
fen.show()
sys.exit(app.exec_()) |
Partager