简体   繁体   中英

How to make QProgressBar display updates while another procedure is running in pyqt

I want to be able to show the progress of a procedure while it is running. My problem is that the QProgressBar seems to be frozen while the procedure is running. Below is an example that shows that while execute_procedure is running (first 5 seconds), the progress_bar doesn't visually update even though the thread is emitting.

from PyQt5 import QtWidgets, QtCore
import sys
import time


class ProgressThread(QtCore.QThread):
    progress_changed = QtCore.pyqtSignal(int)

    def __init__(self):
        super().__init__()

    def run(self):
        completed = 0
        max_time = 15

        increment = float(100 / max_time)
        while completed < 100:
            completed += increment
            time.sleep(1)
            self.progress_changed.emit(completed)
            # print('emitted ', completed) -- this is emitting while 
            # execute_procedure is running but the progress bar 
            # is not visually updating until the procedure is completed             


class TestProgress(QtWidgets.QDialog):
    def __init__(self):
        super().__init__()

        self.tab = QtWidgets.QWidget()
        self.tab.setGeometry(300, 300, 1000, 200)

        self.button_execute = QtWidgets.QPushButton("Execute", self.tab)
        self.button_execute.clicked.connect(self.on_click)

        self.progress_bar = QtWidgets.QProgressBar(self.tab)
        self.progress_bar.move(0, 40)
        self.progress_bar.setProperty("value", 100)

        self.worker = ProgressThread()
        self.worker.progress_changed.connect(self.update_progress_bar)

        self.tab.show()

    def on_click(self):
        self.worker.start()
        self.execute_procedure()

    def execute_procedure(self):
        # while this procedure is running, the progress bar is not updating
        cnt = 0
        while cnt <= 5:
            cnt += 1
            time.sleep(1)

    def update_progress_bar(self, value):
        self.progress_bar.setValue(value)


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    window = TestProgress()
    sys.exit(app.exec_())

You cannot and should not execute a blocking task in the main thread since it prevents the GUI from executing its task correctly.

There are 2 options depending on the use of time.sleep:

  • If the task of time.sleep() is just to give a delay T seconds then use a QTimer .

     # ... class TestProgress(QtWidgets.QDialog): # ... def execute_procedure(self): self.counter = 0 QtCore.QTimer.singleShot(1000, self.execute_counter) def execute_counter(self): if self.counter <= 5: self.counter += 1 QtCore.QTimer.singleShot(1000, self.execute_counter) # ...
  • If in case time.sleep() emulates a task that consumes T seconds then execute it in another thread.

     import threading # ... class TestProgress(QtWidgets.QDialog): # ... def on_click(self): self.worker.start() threading.Thread(target=self.execute_procedure, daemon=True).start() # ...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM