如何从带参数的独立函数更新 PyQt 进度条?

How to update PyQt progressbar from an independent function with arguments?

我想使用多个带参数的导入函数,这些函数需要一些时间 运行。我想要一个 'working' 进度条来跟踪该函数的进程。我已经在这里关注了 2 个问题。

  1. Connect an imported function to Qt5 progress bar without dependencies

区别在于线程可以接受任何可以有参数的函数。该函数也不需要 yield 到 return 的百分比到进度条。进度条始终从 0% 开始。

我从第一个 link 中复制了一个片段,并出于示例目的对其进行了修改。

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) 

不要把答案弄得太复杂,因为它们仅限于非常特定的上下文。一般来说,逻辑是将一个 QObject 传递给它,更新百分比值,然后发出具有该值的信号。例如,一个简单的解决方案是使用线程模块:

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_())