我正在尝试理解如何从QThread向启动的Gui界面发送信号。设置:我有一个需要几乎无限运行(或至少长时间运行)的进程(模拟)。在运行时,它执行各种计算,并且其中一些结果必须发送回GUI,该GUI将实时适当地显示它们。我正在使用PyQt进行GUI设计。我最初尝试使用Python的线程模块,然后在阅读了这里和其他地方的多篇文章后切换到QThreads。根据Qt Blog上的这篇文章You're doing it wrong,使用QThread的首选方法是创建QObject,然后将其移动到QThread中。因此,我遵循了这个SO问题Background thread with QThread in PyQt">的建议,并尝试了一个简单的测试应用程序(下面是代码):它打开一个简单的GUI,让您启动后台进程,并应该更新SpinBox中的步骤值。但它不起作用。GUI从未更新。我做错了什么?
import time, sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class SimulRunner(QObject):
'Object managing the simulation'
stepIncreased = pyqtSignal(int, name = 'stepIncreased')
def __init__(self):
super(SimulRunner, self).__init__()
self._step = 0
self._isRunning = True
self._maxSteps = 20
def longRunning(self):
while self._step < self._maxSteps and self._isRunning == True:
self._step += 1
self.stepIncreased.emit(self._step)
time.sleep(0.1)
def stop(self):
self._isRunning = False
class SimulationUi(QDialog):
'PyQt interface'
def __init__(self):
super(SimulationUi, self).__init__()
self.goButton = QPushButton('Go')
self.stopButton = QPushButton('Stop')
self.currentStep = QSpinBox()
self.layout = QHBoxLayout()
self.layout.addWidget(self.goButton)
self.layout.addWidget(self.stopButton)
self.layout.addWidget(self.currentStep)
self.setLayout(self.layout)
self.simulRunner = SimulRunner()
self.simulThread = QThread()
self.simulRunner.moveToThread(self.simulThread)
self.simulRunner.stepIncreased.connect(self.currentStep.setValue)
self.connect(self.stopButton, SIGNAL('clicked()'), self.simulRunner.stop)
self.connect(self.goButton, SIGNAL('clicked()'), self.simulThread.start)
self.connect(self.simulRunner,SIGNAL('stepIncreased'), self.currentStep.setValue)
if __name__ == '__main__':
app = QApplication(sys.argv)
simul = SimulationUi()
simul.show()
sys.exit(app.exec_())
simulThread
正在运行longRunning
,因此该信号只能在该方法退出后才能被处理,这就是为什么它实际上并没有停止计数器。要这样做,必须从不同的线程(例如主GUI线程)调用“stop”。如果已停止,则需要重置_isRunning
标志才能重新启动计数器,但这超出了问题的原始范围。尽管如此,我在这里发布了一个更完整的示例(仍然有一些可以改进的地方...)。 - mataself.simulRunner
实际上是由创建它的线程拥有的(因为它是其成员所属类的实例)。你应该创建simulRunner
的实例(不带self
),连接所有需要连接的内容(包括添加self.simulThread.finished.connect(simulRunner.deleteLater)
以正确清理),将其移动到self.simulThread
,就这样。至少这是C++ API(和文档)告诉你应该这样做的方式。 - rbaleksandar