pyqt5
Einführung in Fortschrittsbalken
Suche…
Einführung
Fortschrittsbalken sind ein wesentlicher Bestandteil der Benutzererfahrung und helfen Benutzern, einen Überblick über die verbleibende Zeit für einen bestimmten Prozess zu erhalten, der auf der GUI ausgeführt wird. Dieses Thema behandelt die Grundlagen der Implementierung einer Fortschrittsleiste in Ihrer eigenen Anwendung.
Dieses Thema wird leicht auf QThread und den neuen Mechanismus für Signale / Slots eingehen. Einige Grundkenntnisse der PyQt5-Widgets werden auch von Lesern erwartet.
Verwenden Sie beim Hinzufügen von Beispielen nur die integrierten PyQt5- und Python-Ins, um die Funktionalität zu demonstrieren.
Nur PyQt5
Bemerkungen
Das Experimentieren mit diesen Beispielen ist der beste Weg, um mit dem Lernen zu beginnen.
Grundlegende PyQt-Fortschrittsleiste
Dies ist eine sehr grundlegende Fortschrittsanzeige, die nur das Nötigste verwendet.
Es wäre klug, dieses ganze Beispiel bis zum Ende zu lesen.
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_())
Die Fortschrittsleiste wird zuerst so importiert wie from PyQt5.QtWidgets import QProgressBar
Dann wird es wie jedes andere Widget in QtWidgets
Die self.progress.setGeometry(0, 0, 300, 25)
definiert die self.progress.setGeometry(0, 0, 300, 25)
x,y
Positionen im Dialogfeld sowie Breite und Höhe der Fortschrittsleiste.
Dann bewegen wir den Button mit .move()
um 30px
nach unten, so dass zwischen den beiden Widgets ein Abstand von 5px
.
Hier wird self.progress.setValue(count)
verwendet, um den Fortschritt zu aktualisieren. Wenn Sie mit .setMaximum()
einen Maximalwert .setMaximum()
werden die Werte automatisch für Sie berechnet. Wenn der Maximalwert beispielsweise auf 50 TIME_LIMIT
ist, TIME_LIMIT
100 und TIME_LIMIT
von 0 auf 2 bis 4 Prozent statt von 0 auf 1 bis 2 pro Sekunde. Sie können auch einen Mindestwert .setMinimum()
indem Sie .setMinimum()
, um den Fortschrittsbalken zu zwingen, von einem bestimmten Wert zu starten.
Wenn Sie dieses Programm ausführen, wird eine ähnliche GUI erzeugt.
Wie Sie sehen, wird die GUI definitiv einfrieren und reagiert nicht, bis der Zähler die TIME_LIMIT
Bedingung erfüllt. Dies liegt daran, dass time.sleep
das Betriebssystem zu der Überzeugung bringt, dass das Programm in einer Endlosschleife time.sleep
geblieben ist.
QThread
Wie überwinden wir dieses Problem? Wir können die von PyQt5 bereitgestellte Threading-Klasse verwenden.
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_())
Lassen Sie uns diese Modifikationen abbauen.
from PyQt5.QtCore import QThread, pyqtSignal
Diese Zeile importiert Qthread
, eine PyQt5
Implementierung, um einige Teile (z. B. Funktionen, Klassen) eines Programms im Hintergrund zu teilen und auszuführen (auch als Multithreading bekannt). Diese Teile werden auch als Threads bezeichnet. Alle PyQt5
Programme verfügen standardmäßig über einen Haupt-Thread und die anderen (Worker-Threads) werden verwendet, um zusätzliche zeitaufwendige und prozessintensive Aufgaben in den Hintergrund zu verlagern, während das Hauptprogramm weiterhin funktioniert.
Das zweite Import- pyqtSignal
wird verwendet, um Daten (Signale) zwischen pyqtSignal
und Main-Threads zu senden. In diesem Fall werden wir es verwenden, um dem Haupt-Thread mitzuteilen, dass der Fortschrittsbalken aktualisiert werden soll.
Nun haben wir die while-Schleife für den Zähler in eine separate Klasse namens External
verschoben.
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)
Durch die Unterklassifizierung von QThread
wir im Wesentlichen External
in eine Klasse, die in einem separaten Thread ausgeführt werden kann. Darüber hinaus können Threads jederzeit gestartet oder gestoppt werden, was die Vorteile erhöht.
countChanged
ist der aktuelle Fortschritt, und pyqtSignal(int)
teilt dem Worker-Thread mit, dass das gesendete Signal vom Typ int
. self.countChanged.emit(count)
sendet das Signal einfach an alle Verbindungen im Haupt-Thread (normalerweise kann es auch mit anderen Worker-Threads kommunizieren).
def onButtonClick(self):
self.calc = External()
self.calc.countChanged.connect(self.onCountChanged)
self.calc.start()
def onCountChanged(self, value):
self.progress.setValue(value)
Wenn Sie auf die Schaltfläche self.onButtonClick
wird self.onButtonClick
ausgeführt und der Thread gestartet. Der Thread wird mit .start()
gestartet. Es sollte auch beachtet werden, dass wir das self.calc.countChanged
erstellte Signal self.calc.countChanged
mit der zum Aktualisieren des Fortschrittsbalkenwerts verwendeten Methode verbunden haben. Bei jeder Aktualisierung von External::run::count
wird der int
Wert auch an onCountChanged
gesendet.
So könnte die GUI nach diesen Änderungen aussehen.
Es sollte sich auch viel ansprechender anfühlen und wird nicht einfrieren.