pyqt5
Introduktion till Progress Barer
Sök…
Introduktion
Framstegsstänger är en integrerad del av användarupplevelsen och hjälper användare att få en idé om tiden kvar för en given process som körs på GUI. Detta ämne kommer att gå igenom grunderna för att implementera en framstegsfält i din egen applikation.
Detta ämne kommer att beröra lätt på QThread och den nya signalen / slots-mekanismen. En del grundläggande kunskaper om PyQt5-widgets förväntas också av läsarna.
När du lägger till exempel använder du bara PyQt5 och Python inbyggda för att visa funktionalitet.
Endast PyQt5
Anmärkningar
Att experimentera med dessa exempel är det bästa sättet att börja lära sig.
Grundläggande PyQt Progress Bar
Detta är en väldigt grundläggande framstegsfält som bara använder det som behövs på ett minimum.
Det skulle vara klokt att läsa hela detta exempel till slutet.
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_())
Framstegsfältet importeras först så from PyQt5.QtWidgets import QProgressBar
Sedan initialiseras den som alla andra widgetar i QtWidgets
self.progress.setGeometry(0, 0, 300, 25)
definierar positionerna x,y
i dialogrutan och bredden och höjden på framstegsfältet.
Vi flyttar sedan knappen med .move()
med 30px
nedåt så att det blir ett mellanrum på 5px
mellan de två widgetarna.
Här används self.progress.setValue(count)
för att uppdatera framstegen. Att ställa in ett maximivärde med .setMaximum()
kommer också automatiskt att beräkna värdena för dig. Till exempel, om det maximala värdet ställs in som 50, då TIME_LIMIT
är 100 kommer det att hoppa från 0 till 2 till 4 procent istället för 0 till 1 till 2 varje sekund. Du kan också ställa in ett .setMinimum()
med .setMinimum()
tvinga framstegsfältet att starta från ett givet värde.
Att genomföra detta program kommer att ge ett GUI som liknar detta.
Som ni ser kommer GUI definitivt att frysa och inte svara tills räknaren uppfyller TIME_LIMIT
villkoret. Det beror på att time.sleep
får OS att tro att programmet har fastnat i en oändlig slinga.
QThread
Så hur löser vi denna fråga? Vi kan använda trådklassen som PyQt5 tillhandahåller.
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_())
Låt oss dela upp dessa ändringar.
from PyQt5.QtCore import QThread, pyqtSignal
Denna rad importerar Qthread
som är en PyQt5
implementering för att dela upp och köra vissa delar (t.ex. funktioner, klasser) i ett program i bakgrunden (även känd som multitrådning). Dessa delar kallas också trådar. Alla PyQt5
program har som standard en huvudtråd och de andra (arbetartrådar) används för att ladda extra tidskrävande och bearbeta intensiva uppgifter i bakgrunden samtidigt som huvudprogrammets funktion fungerar.
Den andra importen pyqtSignal
används för att skicka data (signaler) mellan arbetare och huvudtrådar. I det här fallet kommer vi att använda den för att berätta för huvudtråden att uppdatera framstegsfältet.
Nu har vi flyttat stundslingan för räknaren till en separat klass som heter 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)
Genom att underklassera QThread QThread
vi i huvudsak External
till en klass som kan köras i en separat tråd. Trådar kan också startas eller stoppas när som helst och lägga till sina fördelar.
Här countChanged
är den aktuella utvecklingen och pyqtSignal(int)
berättar för arbetartråden att signalen som skickas är av typen int
. Medan self.countChanged.emit(count)
helt enkelt skickar signalen till alla anslutningar i huvudtråden (normalt kan den också användas för att kommunicera med andra arbetartrådar).
def onButtonClick(self):
self.calc = External()
self.calc.countChanged.connect(self.onCountChanged)
self.calc.start()
def onCountChanged(self, value):
self.progress.setValue(value)
När du self.onButtonClick
på self.onButtonClick
körs self.onButtonClick
och startar också tråden. Tråden startas med .start()
. Det bör också noteras att vi anslöt signalen self.calc.countChanged
vi skapade tidigare till den metod som användes för att uppdatera framstegsfältets värde. Varje gång External::run::count
uppdateras skickas int
värdet också till onCountChanged
.
Så här kan GUI se ut efter att ha gjort dessa ändringar.
Det borde också känna mycket mer lyhörd och inte frysa.