ste*_*ano 10 python pyqt pyqt4 qthread
这是我之前发布的前一个问题的后续问题.问题是当使用NOT子类化Qthread的推荐方法时,如何从GUI停止(终止|退出)QThread,而是使用QObject然后将其移动到QThread.下面是一个工作实例.我可以启动GUI和Qthread,我可以让后者更新GUI.但是,我无法阻止它.我为qthread(quit(),exit(),甚至terminate())尝试了几种方法无济于事.非常感谢.
这是完整的代码:
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.stopButton.clicked.connect(simulThread.qui) # also tried exit() and terminate()
# also tried the following (didn't work)
# self.stopButton.clicked.connect(self.simulRunner.stop)
self.goButton.clicked.connect(self.simulThread.start)
self.simulThread.started.connect(self.simulRunner.longRunning)
self.simulRunner.stepIncreased.connect(self.current.step.setValue)
if __name__ == '__main__':
app = QApplication(sys.argv)
simul = SimulationUi()
simul.show()
sys.exit(app.exec_())
Run Code Online (Sandbox Code Playgroud)
我很久以前就知道了,但我偶然发现了同样的问题.
我一直在寻找一种合适的方法来做到这一点.最后很容易.退出应用程序时,需要停止任务,并且需要停止调用其退出方法的线程.请参见底部的stop_thread方法.你需要等待线程完成.否则你将得到QThread:当线程仍然在退出时运行'消息时被销毁.
(我也改变了我的代码使用pyside)
import time, sys
from PySide.QtCore import *
from PySide.QtGui import *
class Worker(QObject):
'Object managing the simulation'
stepIncreased = Signal(int)
def __init__(self):
super(Worker, self).__init__()
self._step = 0
self._isRunning = True
self._maxSteps = 20
def task(self):
if not self._isRunning:
self._isRunning = True
self._step = 0
while self._step < self._maxSteps and self._isRunning == True:
self._step += 1
self.stepIncreased.emit(self._step)
time.sleep(0.1)
print "finished..."
def stop(self):
self._isRunning = False
class SimulationUi(QDialog):
def __init__(self):
super(SimulationUi, self).__init__()
self.btnStart = QPushButton('Start')
self.btnStop = QPushButton('Stop')
self.currentStep = QSpinBox()
self.layout = QHBoxLayout()
self.layout.addWidget(self.btnStart)
self.layout.addWidget(self.btnStop)
self.layout.addWidget(self.currentStep)
self.setLayout(self.layout)
self.thread = QThread()
self.thread.start()
self.worker = Worker()
self.worker.moveToThread(self.thread)
self.worker.stepIncreased.connect(self.currentStep.setValue)
self.btnStop.clicked.connect(lambda: self.worker.stop())
self.btnStart.clicked.connect(self.worker.task)
self.finished.connect(self.stop_thread)
def stop_thread(self):
self.worker.stop()
self.thread.quit()
self.thread.wait()
if __name__ == '__main__':
app = QApplication(sys.argv)
simul = SimulationUi()
simul.show()
sys.exit(app.exec_())
Run Code Online (Sandbox Code Playgroud)
我发现我原来的问题实际上是两个问题合二为一:为了停止主线程的辅助线程,你需要两件事:
能够从主线程向下通信到辅助线程
发送适当的信号来停止线程
我无法解决(2),但我想出了如何解决(1),这为我原来的问题提供了解决方法。我可以停止线程的处理(方法longRunning()) ,而不是停止线程
问题是辅助线程只有运行自己的事件循环才能响应信号。常规的 Qthread(这是我的代码使用的)则不然。不过,将 QThread 子类化以达到这种效果是很容易的:
class MyThread(QThread):
def run(self):
self.exec_()
Run Code Online (Sandbox Code Playgroud)
并在我的代码中使用self.simulThread = MyThread()而不是原来的self.simulThread = Qthread(). 这确保辅助线程运行事件循环。但这还不够。该longRunning()方法需要有机会实际处理来自主线程的事件。在这个 SO 答案的帮助下,我发现QApplication.processEvent()在longRunning()方法中简单添加 a 给了辅助线程这样的机会。我现在可以停止在辅助线程中执行的处理,即使我还没有弄清楚如何停止线程本身。
总结一下。我的 longRunning 方法现在如下所示:
def longRunning(self):
while self._step < self._maxSteps and self._isRunning == True:
self._step += 1
self.stepIncreased.emit(self._step)
time.sleep(0.1)
QApplication.processEvents()
Run Code Online (Sandbox Code Playgroud)
我的 GUI 线程有以下三行来完成这项工作(除了上面列出的 QThread 子类之外):
self.simulThread = MyThread()
self.simulRunner.moveToThread(self.simulThread)
self.stopButton.clicked.connect(self.simulRunner.stop)
Run Code Online (Sandbox Code Playgroud)
欢迎评论!