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
| #!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
from time import sleep
from random import random, randint
import multiprocessing as mp # pour le calcul en parallele
from PyQt5 import QtCore, QtGui, QtWidgets
##############################################################################
def fncalcul(x):
"""simule un calcul long
"""
sleep(random()) # temps de calcul au hasard entre 0 et 1 seconde
return [x, 2*x]
##############################################################################
class MonThread(QtCore.QThread):
"""Lance le calcul en parallèle et renseigne le graphique par signal pour
mise à jour de la barre de progression
"""
# nouveau signal pour envoyer les résultats des calculs: [donnée, résultat]
inforesultat = QtCore.pyqtSignal(list)
# nouveau signal pour indiquer la fin du thread avec message de fin
infofincalculs = QtCore.pyqtSignal(str)
#=========================================================================
def __init__(self, calcul, datas, parent=None):
super().__init__(parent)
self.calcul = calcul # fonction de calcul
self.datas = datas # liste des données à calculer
#=========================================================================
def run(self):
"""partie assynchrone du thread
"""
# fait les calculs en parallele(CPU multicores)
with mp.Pool(processes=mp.cpu_count()) as pool:
for resultat in pool.imap(self.calcul, self.datas):
self.inforesultat.emit(resultat) # envoi le résultat
# envoie le message de fin des calculs
self.infofincalculs.emit("Calculs terminés")
#############################################################################
class Fenetre(QtWidgets.QWidget):
#========================================================================
def __init__(self, parent=None):
super().__init__(parent)
self.resize(250, 150)
self.setWindowTitle('ProgressBar')
# crée et initialise la barre de progression
self.pbar = QtWidgets.QProgressBar(self)
self.pbar.setAlignment(QtCore.Qt.AlignHCenter)
self.pbar.setRange(0, 100) # pour affichage de pourcentages
# crée le bouton de lancement des calculs
self.bouton = QtWidgets.QPushButton('Départ', self)
self.bouton.clicked.connect(self.lancement)
# positionne les widgets dans la fenêtre
posit = QtWidgets.QGridLayout()
posit.addWidget(self.pbar, 0, 0)
posit.addWidget(self.bouton, 1, 0)
self.setLayout(posit)
# prépare la liste des 100 données à calculer
self.datas = [randint(1,1000) for data in range(0, 100)]
self.nbdatas = len(self.datas) # nombre total de données
# initialise les variables utilisées plus loin
self.nb = 0 # nombre de calculs déjà faits
self.monthread = None # si None, aucun calcul n'est en cours
#========================================================================
def lancement(self):
"""Lance le thread de calcul
"""
if self.monthread!=None:
# un calcul est déjà en cours: on ne fait rien
return
# crée et initialise le thread de calcul
self.monthread = MonThread(fncalcul, self.datas)
# crée les liens pour recevoir les informations du thread par signaux
self.monthread.inforesultat.connect(self.recupresultat)
self.monthread.infofincalculs.connect(self.fincalculs)
# réinitialise le nombre de calcul fait
self.nb = 0
# réinitialise la barre de progression si elle a déjà été utilisée
self.pbar.reset()
# lance le thread
self.monthread.start()
#========================================================================
def recupresultat(self, resultat):
"""Reçoit chaque résultat calculé obtenu
"""
# met à jour la barre de progression
self.nb += 1 # un résultat de plus
self.pbar.setValue(int(self.nb*100/self.nbdatas))
# exploite le résultat qui vient d'être calculé
data, result = resultat
# ...
print(data, result) # affichage en console
# ...
#========================================================================
def fincalculs(self, msg):
"""Reçoit le signal de fin du thread avec son message
"""
# désactive les liens avec le thread
self.monthread.inforesultat.disconnect()
self.monthread.infofincalculs.disconnect()
# dit que le calcul est terminé
self.monthread = None
# affiche le 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