我相信bnaecker、Brendan Abel和Steve 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 的事实有关(这就是我从这里得到的,至少)。尽管如此,这似乎足以证明工人的任务在不同的线程上运行。如果有人有更准确的信息,请随时扩展。
对于那些想了解更多关于这个主题的人,这里是许多文章引用的链接。