I want to use multiple imported function with arguments that takes some while to run. I want a ‘working’ progress bar that track the processes of that function. I have followed 2 questions already here.
- Connect an imported function to Qt5 progress bar without dependencies
- Report progress to QProgressBar using variable from an imported module
The difference is that the thread can take any function which can have arguments. The function also not needs to yield
the percent to return to the progressbar. The progressbar always start at 0%.
I copied a snippet from first link and modified it for example purpose.
from external_script import long_running_function class Actions(QDialog): def __init__(self): super().__init__() self.initUI() def initUI(self): self.setWindowTitle('Progress Bar') self.progress = QProgressBar(self) self.button = QPushButton('Start', self) self.show() self.button.clicked.connect(self.onButtonClick) def onButtonClick(self): long_running_function(**kwargs) # This can be any function that takes argument/s self.progress.setValue(value)
Advertisement
Answer
Do not get too complicated with the answers as they are limited to a very particular context. In general the logic is to pass a QObject to it that updates the percentage value and then emits a signal with that value. For example a simple solution is to use the threading module:
import sys import threading from PyQt5 import QtCore, QtWidgets class PercentageWorker(QtCore.QObject): started = QtCore.pyqtSignal() finished = QtCore.pyqtSignal() percentageChanged = QtCore.pyqtSignal(int) def __init__(self, parent=None): super().__init__(parent) self._percentage = 0 @property def percentage(self): return self._percentage @percentage.setter def percentage(self, value): if self._percentage == value: return self._percentage = value self.percentageChanged.emit(self.percentage) def start(self): self.started.emit() def finish(self): self.finished.emit() class FakeWorker: def start(self): pass def finish(self): pass @property def percentage(self): return 0 @percentage.setter def percentage(self, value): pass import time def long_running_function(foo, baz="1", worker=None): if worker is None: worker = FakeWorker() worker.start() while worker.percentage < 100: worker.percentage += 1 print(foo, baz) time.sleep(1) worker.finish() class Widget(QtWidgets.QWidget): def __init__(self, parent=None): super().__init__(parent) self.progress = QtWidgets.QProgressBar() self.button = QtWidgets.QPushButton("Start") lay = QtWidgets.QVBoxLayout(self) lay.addWidget(self.button) lay.addWidget(self.progress) self.button.clicked.connect(self.launch) def launch(self): worker = PercentageWorker() worker.percentageChanged.connect(self.progress.setValue) threading.Thread( target=long_running_function, args=("foo",), kwargs=dict(baz="baz", worker=worker), daemon=True, ).start() if __name__ == "__main__": app = QtWidgets.QApplication(sys.argv) w = Widget() w.show() sys.exit(app.exec_())