1

我想在与我的其余代码不同的线程中运行进度条,但我想控制进度条如何从我的主线程更新。

这是可能的吗?

这是我到目前为止所拥有的:

import time
from PySide import QtGui
from PySide import QtCore
from PySide import QtUiTools

class progressBar(QtGui.QDialog, QtCore.QThread):

    def __init__(self, window, title=None):
        super(progressBar, self).__init__(window)
        QtCore.QThread.__init__(self)

        self.title = title or 'Progress'
        self.setupUi()
        self.show()

    def setupUi(self):
        self.setObjectName("Thinking")
        self.gridLayout = QtGui.QGridLayout(self)
        self.gridLayout.setObjectName("gridLayout")
        self.progressBar = QtGui.QProgressBar(self)
        self.gridLayout.addWidget(self.progressBar, 0, 0, 1, 1)

        # ADJUSTMENTS
        self.setMaximumSize(280, 50)
        self.setMinimumSize(280, 50)
        self.setWindowTitle(self.title)


    def increase(self, inc):
        self.progressBar.setProperty("value", inc)
        time.sleep(0.01)

    def run(self):
        for i in range(1,101):
            self.increase(i)



progressThread = progressBar(QtGui.QApplication.activeWindow())
progressThread.start()

这似乎是在线程内正确运行进度条,但它完全由 run 函数控制。

我尝试删除 run 函数并将此代码添加到我的主线程:

progressThread = progressBar(QtGui.QApplication.activeWindow())
progressThread.start()

for i in range(1,101):
    progressThread.increase(i)

但这似乎不起作用。

对此的任何帮助都会很棒...谢谢

4

1 回答 1

2

我相信bnaeckerBrendan AbelSteve Cohen已经在他们的评论中为您提供了关键信息。正如他们已经说过的,如果 UI 在主线程上运行,您绝对可以在单独的线程中运行进度条和逻辑。

这是一个应该按照您想要的方式工作的示例:

import time, random
import threading

from PySide import QtCore, QtGui


class ProgressWidget(QtGui.QWidget):

    # just for the purpose of this example,
    # define a fixed number of threads to run
    nthreads = 6

    def __init__(self):
        super(ProgressWidget, self).__init__()
        self.threads = []
        self.workers = []
        self.works = [0 for i in range(self.nthreads)]
        self.setupUi()
        self.setupWorkers()
        self.runThreads()

    def drawProgessBar(self):
        self.progressBar = QtGui.QProgressBar(self)
        self.progressBar.setGeometry(QtCore.QRect(20, 20, 582, 24))
        self.progressBar.minimum = 1
        self.progressBar.maximum = 100
        self.progressBar.setValue(0)

    def setupUi(self):
        self.setWindowTitle("Threaded Progress")
        self.resize(600, 60)
        self.drawProgessBar()

    def buildWorker(self, index):
        """a generic function to build multiple workers;
        workers will run on separate threads and emit signals
        to the ProgressWidget, which lives in the main thread
        """
        thread = QtCore.QThread()
        worker = Worker(index)
        worker.updateProgress.connect(self.handleProgress)
        worker.moveToThread(thread)
        thread.started.connect(worker.work)
        worker.finished.connect(thread.quit)
        QtCore.QMetaObject.connectSlotsByName(self)
        # retain a reference in the main thread
        self.threads.append(thread)
        self.workers.append(worker)

    def setupWorkers(self):
        for i in range(self.nthreads):
            self.buildWorker(i)

    def runThreads(self):
        for thread in self.threads:
            thread.start()

    def handleProgress(self, signal):
        """you can add any logic you want here,
        it will be executed in the main thread
        """
        index, progress = signal
        self.works[index] = progress
        value = 0
        for work in self.works:
            value += work
        value /= float(self.nthreads)
        # management of special cases
        if value >= 100:
            self.progressBar.hide()
            return
        # else
        self.progressBar.setValue(value)
        print 'progress (ui) thread: %s  (value: %d)' % (threading.current_thread().name, value)


class Worker(QtCore.QObject):
    """the worker for a threaded process;
    (this is created in the main thread and
    then moved to a QThread, before starting it)
    """

    updateProgress = QtCore.Signal(tuple)
    finished = QtCore.Signal(int)

    def __init__(self, index):
        super(Worker, self).__init__()
        # store the Worker index (for thread tracking
        # and to compute the overall progress)
        self.id = index

    def work(self): 
        for i in range(100):
            print 'worker thread: %s' % (threading.current_thread().name, )
            # simulate some processing time
            time.sleep(random.random() * .2)
            # emit progress signal
            self.updateProgress.emit((self.id, i + 1))
        # emit finish signal
        self.finished.emit(1)


if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    ui = ProgressWidget()
    ui.show()
    sys.exit(app.exec_())

这是一个最小的细分:

  • QThreads 存在于创建它们的主线程中(而不是它们管理的线程中)
  • 为了在单独的线程上运行任务,必须使用该moveToThread方法将它们传递给 QThreads(工作人员需要子类化QObject该方法才能使用)
  • 工作人员发送信号以更新进度条并通知他们已完成任务
  • 在这个例子中,我们正在运行多个任务,每个任务都在自己的线程中。进度信号被发送回主线程,更新进度条的逻辑在主线程中运行

附注:在控制台中,工作人员的输出指的是“虚拟”线程。这似乎与threading模块不了解 QThreads 的事实有关(这就是我从这里得到的,至少)。尽管如此,这似乎足以证明工人的任务在不同的线程上运行。如果有人有更准确的信息,请随时扩展。

对于那些想了解更多关于这个主题的人,这里是许多文章引用的链接。

于 2017-06-24T18:35:04.590 回答