0

我一直在尝试找到一种同时运行和更新多个进度条的方法,但到目前为止我运气不佳。我想我还需要一个查询/运行/重置系统才能使其工作。

有任何想法吗?我一直在玩 QThreadPool 和 QRunnable,但没有成功。


** 更新:根据这篇很棒的文章更新了代码。它似乎有效,但存在许多问题:

  • 我收到警告:QObject::startTimer: timers cannot be started from another thread

  • 一旦我更改了 execute_this_fn 函数中的更新频率(比如更新 1、2、3 等),整个事情就会崩溃。

  • 我希望能够将进度条的数量限制为 3。如果我单击开始按钮超过 3 次,它们应该被查询。


from PySide.QtGui import *
from PySide.QtCore import *

import time
import traceback, sys

class WorkerSignals(QObject):
    finished = Signal()
    error = Signal(tuple)
    result = Signal(object)
    progress = Signal(int)

class Worker(QRunnable):
    def __init__(self, fn, bar, *args, **kwargs):
        super(Worker, self).__init__()
        self.fn = fn
        self.bar = bar
        self.args = args
        self.kwargs = kwargs
        self.signals = WorkerSignals()

        # Add the callback to our kwargs
        kwargs['progress_callback'] = self.signals.progress

    @Slot()
    def run(self):
        # Retrieve args/kwargs here; and fire processing using them
        try:
            result = self.fn(self.bar, *self.args, **self.kwargs)
        except:
            traceback.print_exc()
            exctype, value = sys.exc_info()[:2]
            self.signals.error.emit((exctype, value, traceback.format_exc()))
        else:
            self.signals.result.emit(result)  # Return the result of the processing
        finally:
            self.signals.finished.emit()  # Done

class MainWindow(QMainWindow):

    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)

        self.counter = 0

        self.layout = QVBoxLayout()

        b = QPushButton("Start thread")
        b.pressed.connect(self.start_me)

        self.layout.addWidget(b)

        w = QWidget()
        w.setLayout(self.layout)

        self.setCentralWidget(w)
        self.show()

        self.threadpool = QThreadPool()
        print("Multithreading with maximum %d threads" % self.threadpool.maxThreadCount())

    def progress_fn(self, n):
        print("%d%% done" % n)

    def execute_this_fn(self, bar, progress_callback):
        for n in range(0, 5):
            time.sleep(1)
            calc = n*100/4
            progress_callback.emit(calc)
            bar.setValue(calc)
        return "Done."

    def print_output(self, s):
        print(s)

    def thread_complete(self):
        print("THREAD COMPLETE!")

    def start_me(self):
        # Pass the function to execute
        xx = self.progress_bar = QProgressBar()
        self.layout.addWidget(xx)
        worker = Worker(self.execute_this_fn, xx) # Any other args, kwargs are passed to the run function
        worker.signals.result.connect(self.print_output)
        worker.signals.finished.connect(self.thread_complete)
        worker.signals.progress.connect(self.progress_fn)

        # Execute
        self.threadpool.start(worker)


app = QApplication([])
window = MainWindow()
app.exec_()
4

1 回答 1

1

让它以此为基础工作。

from PySide import QtCore
from PySide import QtGui

import sys
import time

import random
class WorkerSignals(QtCore.QObject):

    finished = QtCore.Signal()
    error = QtCore.Signal(tuple)
    result = QtCore.Signal(object)
    progress = QtCore.Signal(list)

class Worker(QtCore.QRunnable):

    def __init__(self, num, bar):
        super(Worker, self).__init__()
        self.num = num
        self.bar = bar
        self.signals = WorkerSignals()


    def run(self):
        try:

            for i in range(1, 101):
                self.signals.progress.emit([self.bar, i])

                sleep_time = random.uniform(0.01, 0.3)

                time.sleep(sleep_time)

        except Exception as e:
            print "Quit thread {0}".format(self.num)
            return

class Tasks(QtGui.QWidget):
    def __init__(self):
        super(Tasks, self).__init__()


        self.pool = QtCore.QThreadPool.globalInstance()
        self.pool.setMaxThreadCount(5)

        self.layout = QtGui.QVBoxLayout()
        self.btn = QtGui.QPushButton("start")
        self.layout.addWidget(self.btn)

        self.setLayout(self.layout)

        self.btn.clicked.connect(self.start_me)


    def start_me(self):
        for task in range(10):
            xx = QtGui.QProgressBar()
            self.layout.addWidget(xx)
            self.worker = Worker(task, xx)
            self.worker.signals.progress.connect(self.setProgress)
            self.pool.start(self.worker)
        #self.pool.waitForDone()

    def setProgress(self, l):
        bar, num = l
        bar.setValue(num)
        #print l

def main():
    app = QtGui.QApplication(sys.argv)
    panel = Tasks() 
    panel.show()
    app.exec_()


if __name__ == '__main__':
    main()
于 2017-10-02T12:29:10.733 回答