Learn Python PyQt

PyQt progressbar

Still worried about finding Python to do a variety of progress bar beautification?
In this article you learn how to use the QProgressbar and how to create theme variations.

The QProgressBar applications will do some delay operations, which will cause the main thread to get stuck in the UI: The main thread will be waiting for delays, which causes the whole program to hang. That would make the whole program unresponsive.

Threads in PyQt can solve this problem perfectly.

class Thread(QThread):

Book: Create Desktop Apps with Python PyQt5

QProgressBar example

This example uses the time module in python to do the delay operation time.sleep().

It puts the delay operation into the sub-thread to realize the real-time UI refresh of PyQt.

Because the thread is doing the QProgressBar update, it doesn’t cause the main thread to hang.

pyqt progressbar
import sys
import time
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtWidgets import QWidget, QPushButton, QProgressBar, QVBoxLayout, QApplication

class Thread(QThread):
    _signal = pyqtSignal(int)
    def __init__(self):
        super(Thread, self).__init__()

    def __del__(self):
        self.wait()

    def run(self):
        for i in range(100):
            time.sleep(0.1)
            self._signal.emit(i)

class Example(QWidget):
    def __init__(self):
        super(Example, self).__init__()
        self.setWindowTitle('QProgressBar')
        self.btn = QPushButton('Click me')
        self.btn.clicked.connect(self.btnFunc)
        self.pbar = QProgressBar(self)
        self.pbar.setValue(0)
        self.resize(300, 100)
        self.vbox = QVBoxLayout()
        self.vbox.addWidget(self.pbar)
        self.vbox.addWidget(self.btn)
        self.setLayout(self.vbox)
        self.show()

    def btnFunc(self):
        self.thread = Thread()
        self.thread._signal.connect(self.signal_accept)
        self.thread.start()
        self.btn.setEnabled(False)

    def signal_accept(self, msg):
        self.pbar.setValue(int(msg))
        if self.pbar.value() == 99:
            self.pbar.setValue(0)
            self.btn.setEnabled(True)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    ex = Example()
    ex.show()
    sys.exit(app.exec_())

Progressbar styles

The example below uses CSS stylesheet to make variations of the QProgressBar.

QProgressBar styles for pyqt
from random import randint
import sys
from PyQt5.QtCore import QTimer
from PyQt5.QtWidgets import QWidget, QApplication, QVBoxLayout, QProgressBar

StyleSheet = '''
#RedProgressBar {
    text-align: center;
}
#RedProgressBar::chunk {
    background-color: #F44336;
}
#GreenProgressBar {
    min-height: 12px;
    max-height: 12px;
    border-radius: 6px;
}
#GreenProgressBar::chunk {
    border-radius: 6px;
    background-color: #009688;
}
#BlueProgressBar {
    border: 2px solid #2196F3;
    border-radius: 5px;
    background-color: #E0E0E0;
}
#BlueProgressBar::chunk {
    background-color: #2196F3;
    width: 10px; 
    margin: 0.5px;
}
'''


class ProgressBar(QProgressBar):

    def __init__(self, *args, **kwargs):
        super(ProgressBar, self).__init__(*args, **kwargs)
        self.setValue(0)
        if self.minimum() != self.maximum():
            self.timer = QTimer(self, timeout=self.onTimeout)
            self.timer.start(randint(1, 3) * 1000)

    def onTimeout(self):
        if self.value() >= 100:
            self.timer.stop()
            self.timer.deleteLater()
            del self.timer
            return
        self.setValue(self.value() + 1)


class Window(QWidget):

    def __init__(self, *args, **kwargs):
        super(Window, self).__init__(*args, **kwargs)
        self.resize(800, 600)
        layout = QVBoxLayout(self)
        layout.addWidget(  
            ProgressBar(self, minimum=0, maximum=100, objectName="RedProgressBar"))

        layout.addWidget(  
            ProgressBar(self, minimum=0, maximum=0, objectName="RedProgressBar"))

        layout.addWidget(  
            ProgressBar(self, minimum=0, maximum=100, textVisible=False,
                        objectName="GreenProgressBar"))
        layout.addWidget(  
            ProgressBar(self, minimum=0, maximum=0, textVisible=False,
                        objectName="GreenProgressBar"))

        layout.addWidget(  
            ProgressBar(self, minimum=0, maximum=100, textVisible=False,
                        objectName="BlueProgressBar"))
        layout.addWidget(  
            ProgressBar(self, minimum=0, maximum=0, textVisible=False,
                        objectName="BlueProgressBar"))


if __name__ == "__main__":
    app = QApplication(sys.argv)
    app.setStyleSheet(StyleSheet)
    w = Window()
    w.show()
    sys.exit(app.exec_())

When creating progressbars, we use the parameter objectName to set the css class name.

layout.addWidget(  
    ProgressBar(self, minimum=0, maximum=0, objectName="RedProgressBar"))

layout.addWidget(  
    ProgressBar(self, minimum=0, maximum=0, textVisible=False,
                objectName="GreenProgressBar"))

layout.addWidget(  
    ProgressBar(self, minimum=0, maximum=0, textVisible=False,
                objectName="BlueProgressBar"))

You can see they match the styleSheets class names (on top):

#RedProgressBar {
    ...

#GreenProgressBar {
    ...

#BlueProgressBar {
    ...

Book: Create Desktop Apps with Python PyQt5