Il s'agit d'une barre de progression très basique qui n'utilise que ce qui est nécessaire au strict minimum.
Il serait sage de lire cet exemple jusqu'à la fin.
import sys
import time
from PyQt5.QtWidgets import (QApplication, QDialog,
QProgressBar, QPushButton)
TIME_LIMIT = 100
class Actions(QDialog):
"""
Simple dialog that consists of a Progress Bar and a Button.
Clicking on the button results in the start of a timer and
updates the progress bar.
"""
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('Progress Bar')
self.progress = QProgressBar(self)
self.progress.setGeometry(0, 0, 300, 25)
self.progress.setMaximum(100)
self.button = QPushButton('Start', self)
self.button.move(0, 30)
self.show()
self.button.clicked.connect(self.onButtonClick)
def onButtonClick(self):
count = 0
while count < TIME_LIMIT:
count += 1
time.sleep(1)
self.progress.setValue(count)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Actions()
sys.exit(app.exec_())
La barre de progression est d'abord importées comme si from PyQt5.QtWidgets import QProgressBar
Ensuite, il est initialisé comme tout autre widget dans QtWidgets
La ligne méthode self.progress.setGeometry(0, 0, 300, 25)
définit les x,y
positions sur le dialogue et la largeur et la hauteur de la barre de progression.
Nous déplaçons ensuite le bouton en utilisant .move()
par 30px
vers le bas de sorte qu'il y aura un écart de 5px
entre les deux widgets.
Ici self.progress.setValue(count)
est utilisé pour mettre à jour la progression. La définition d'une valeur maximale à l'aide de .setMaximum()
calcule également automatiquement les valeurs pour vous. Par exemple, si la valeur maximale est définie sur 50, alors que TIME_LIMIT
vaut 100, elle sautera de 0 à 2 à 4% au lieu de 0 à 1 à 2 toutes les secondes. Vous pouvez également définir une valeur minimale en utilisant .setMinimum()
pour forcer la barre de progression à démarrer à partir d'une valeur donnée. L'exécution de ce programme produira une interface graphique similaire à celle-ci.
Comme vous pouvez le voir, l'interface graphique sera certainement geler et cesse de répondre jusqu'à ce que le compteur satisfait à la condition TIME_LIMIT
. En effet, time.sleep
fait croire au système d'exploitation que le programme s'est bloqué dans une boucle infinie.
QThread
Alors, comment pouvons-nous surmonter ce problème? Nous pouvons utiliser la classe de threading fournie par PyQt5.
import sys
import time
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtWidgets import (QApplication, QDialog,
QProgressBar, QPushButton)
TIME_LIMIT = 100
class External(QThread):
"""
Runs a counter thread.
"""
countChanged = pyqtSignal(int)
def run(self):
count = 0
while count < TIME_LIMIT:
count +=1
time.sleep(1)
self.countChanged.emit(count)
class Actions(QDialog):
"""
Simple dialog that consists of a Progress Bar and a Button.
Clicking on the button results in the start of a timer and
updates the progress bar.
"""
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('Progress Bar')
self.progress = QProgressBar(self)
self.progress.setGeometry(0, 0, 300, 25)
self.progress.setMaximum(100)
self.button = QPushButton('Start', self)
self.button.move(0, 30)
self.show()
self.button.clicked.connect(self.onButtonClick)
def onButtonClick(self):
self.calc = External()
self.calc.countChanged.connect(self.onCountChanged)
self.calc.start()
def onCountChanged(self, value):
self.progress.setValue(value)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Actions()
sys.exit(app.exec_())
Décrivons ces modifications.
from PyQt5.QtCore import QThread, pyqtSignal
Cette importation de ligne Qthread
qui est une mise en œuvre PyQt5
de diviser et d'exécuter certaines parties (par exemple: fonctions, classes) d'un programme en arrière-plan (aussi connu sous le multi-threading). Ces parties sont également appelées threads.Tous les programmes PyQt5
ont par défaut un thread principal et les autres (threads de travail) sont utilisés pour décharger des tâches très longues et fastidieuses en arrière-plan tout en maintenant le fonctionnement du programme principal.
La deuxième importation pyqtSignal
est utilisée pour envoyer des données (signaux) entre les threads de travail et principaux. Dans ce cas, nous l'utiliserons pour indiquer au thread principal de mettre à jour la barre de progression.
Maintenant, nous avons déplacé la boucle while du compteur dans une classe distincte appelée External
.
class External(QThread):
"""
Runs a counter thread.
"""
countChanged = pyqtSignal(int)
def run(self):
count = 0
while count < TIME_LIMIT:
count +=1
time.sleep(1)
self.countChanged.emit(count)
Par sous-classing QThread
nous convertissons essentiellement External
dans une classe qui peut être exécuté dans un thread séparé. Threads peut également être démarré ou arrêté à tout moment en ajoutant à ses avantages.
Ici countChanged
est la progression en cours et pyqtSignal(int)
indique au thread de travail que le signal envoyé est de type int
. Bien que, self.countChanged.emit(count)
envoie simplement le signal à toutes les connexions dans le thread principal (normalement il peut aussi être utilisé pour communiquer avec d'autres threads de travail).
def onButtonClick(self):
self.calc = External()
self.calc.countChanged.connect(self.onCountChanged)
self.calc.start()
def onCountChanged(self, value):
self.progress.setValue(value)
Lorsque le bouton est cliqué sur le self.onButtonClick
courront et aussi démarrer le fil. Le fil est démarré avec .start()
. Il convient également de noter que nous avons connecté le signal self.calc.countChanged
que nous avons créé précédemment à la méthode utilisée pour mettre à jour la valeur de la barre de progression. Chaque fois que External::run::count
est mis à jour, la valeur int
est également envoyée à onCountChanged
.
Voici comment l'interface graphique peut prendre en charge ces modifications.
Il doit aussi se sentir beaucoup plus réactif et ne gèle pas.
Cela m'a vraiment énormément aidé bien que j'utilise PyQt4 –
@JuanCarlosAsuncion^_ ^ – daegontaven