2013-04-26 80 views
7

我想了解如何使用信号从Qthread回到启动的Gui界面。如何从正在运行的QThread发回PyQt Gui启动它?

安装程序:我有一个需要几乎无限期运行(或至少很长时间)运行的进程(模拟)。运行时,它执行各种计算,其中一些结果必须是发送回GUI,这将实时显示它们。 我正在使用PyQt的GUI。我最初尝试使用python的线程模块,然后在阅读SO和其他地方的几篇文章后转到QThreads。

根据Qt博客You're doing it wrong上的这篇文章,使用QThread的首选方法是创建一个QObject,然后将它移动到Qthread。所以我在后台线程中使用QThread在PyQt“>这个SO问题中尝试了一个简单的测试应用程序(代码如下):它打开了一个简单的GUI,让你启动后台进程,并且它被issupposed更新步骤值。一个纺纱器

但它不工作的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_()) 

回答

7

这里的问题很简单:你SimulRunner永远不会被发送,导致它开始的信号其工作方式之一就是将其连接到线程的started信号。

A在Python中,你应该使用新式的连接信号方式:

... 
self.simulRunner = SimulRunner() 
self.simulThread = QThread() 
self.simulRunner.moveToThread(self.simulThread) 
self.simulRunner.stepIncreased.connect(self.currentStep.setValue) 
self.stopButton.clicked.connect(self.simulRunner.stop) 
self.goButton.clicked.connect(self.simulThread.start) 
# start the execution loop with the thread: 
self.simulThread.started.connect(self.simulRunner.longRunning) 
... 
+1

你是完全正确的,我只是意识到了错误。我从之前版本中删除并粘贴了代码,而不是使用moveToThread,而完全忘记了started()方法。感谢您指出。 – stefano 2013-04-26 18:34:36

+0

这是一个非常有趣的例子。然而,按照这个建议,线程会启动,但停止按钮不会停止它。有一个工作的例子会很棒。也许是一个Go按钮,可以重新启动整个事件 – Fabrizio 2013-08-08 09:49:23

+0

stop只发送一个信号,但是因为'simulThread'忙于运行'longRunning',那个信号只能在该方法退出后才能被处理,这就是为什么它不会真的停止柜台。要做到这一点,'stop'将不会从另一个线程(例如主GUI线程)被调用。要重新启动计数器,您需要重置_isRunning标志(如果它已停止),但这超出了问题的原始范围。尽管如此,我已经发布了一个更完整的示例[这里](http://pastebin.com/kmvLb6Y2)(这里仍然会有一些东西可以被强化......) – mata 2013-08-08 20:42:32