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.