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.

Progress Bar Dialog svarar inte

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.onButtonClickself.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.

QThread Progress Bar

Det borde också känna mycket mer lyhörd och inte frysa.



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow