Python - PyQt:重新启动已完成的线程
Posted
技术标签:
【中文标题】Python - PyQt:重新启动已完成的线程【英文标题】:Python - PyQt: restarting a thread which is finished 【发布时间】:2018-10-09 08:12:46 【问题描述】:我有 pyqt 界面,如果按下按钮,它会启动 QThread。线程运行,完成后我可以再次启动它,到这里没有问题。 我现在为线程的连续操作添加了一个复选框。如果选中复选框,则按钮保持按下状态,并且必须再次按下按钮以停止线程。
显然在停止后,线程已正确完成(也使用isRunning()
方法检查)但如果我尝试在连续操作中再次启动它,程序将崩溃。如果我在关闭连续操作的情况下重新启动它,则不会发生这种情况,但在这种情况下,线程会启动和停止两次。
如何解释这种行为?有没有办法让它按预期工作?
一个例子:
import sys
from PyQt5 import QtCore
import PyQt5.QtWidgets as QtW
from PyQt5.QtCore import QThread, pyqtSlot, pyqtSignal
import time
class MyWindow(QtW.QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('MyWindow')
self._main = QtW.QWidget()
self.setCentralWidget(self._main)
self.button = QtW.QPushButton('Do it', self)
self.button.clicked.connect(self.do)
self.contincheck = QtW.QCheckBox("Continuous")
self.contincheck.clicked.connect(self.continuous_doing)
self.continuous = False
self.layout = QtW.QGridLayout(self._main)
self.layout.addWidget(self.button,0,0)
self.layout.addWidget(self.contincheck,1,0)
self.setLayout(self.layout)
self.show()
def continuous_doing(self):
if self.contincheck.isChecked():
self.button.setCheckable(True)
self.continuous = True
else:
self.button.setCheckable(False)
self.continuous = False
def do(self):
if self.button.isCheckable() and not self.button.isChecked():
self.button.setText('Do it')
self.button.clicked.connect(self.do)
self.contincheck.setEnabled(True)
else:
self.mythread = MyThread(self.continuous)
if self.button.isCheckable() and self.button.isChecked():
self.button.setText('Stop doing that')
self.contincheck.setDisabled(True)
self.button.clicked.connect(self.mythread.stop)
self.mythread.finished.connect(self.thread_finished)
self.mythread.signal.connect(self.done)
self.mythread.start()
@pyqtSlot(int)
def done(self, i):
print('done it', i)
@pyqtSlot()
def thread_finished(self):
print('thread finished')
class MyThread(QThread):
signal = pyqtSignal(int)
def __init__(self, continuous):
QThread.__init__(self)
self._stopped = True
self.continuous = continuous
self.i = 0
def __del__(self):
self.wait()
def stop(self):
self._stopped = True
def run(self):
self._stopped = False
while True:
self.signal.emit(self.i)
if self._stopped:
break
if self.continuous: time.sleep(2)
else: break
if __name__ == '__main__':
app = QtCore.QCoreApplication.instance()
if app is None:
app = QtW.QApplication(sys.argv)
mainGui = MyWindow()
mainGui.show()
app.aboutToQuit.connect(app.deleteLater)
app.exec_()
【问题讨论】:
【参考方案1】:问题是您正在创建一个新线程而不是重用现有线程,在下面的示例中,我将向您展示如何正确执行此操作:
import sys
from PyQt5 import QtCore, QtWidgets
class MyWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('MyWindow')
self._main = QtWidgets.QWidget()
self.setCentralWidget(self._main)
self.button = QtWidgets.QPushButton('Do it')
self.button.clicked.connect(self.do)
self.contincheck = QtWidgets.QCheckBox("Continuous")
self.contincheck.clicked.connect(self.continuous_doing)
self.continuous = False
layout = QtWidgets.QGridLayout(self._main)
layout.addWidget(self.button, 0, 0)
layout.addWidget(self.contincheck, 1, 0)
self.mythread = MyThread(self.continuous, self)
self.mythread.finished.connect(self.thread_finished)
self.button.clicked.connect(self.mythread.stop)
self.mythread.signal.connect(self.done)
def continuous_doing(self):
self.button.setCheckable(self.contincheck.isChecked())
self.continuous = self.contincheck.isChecked()
def do(self):
if self.button.isCheckable() and not self.button.isChecked():
self.button.setText('Do it')
self.contincheck.setEnabled(True)
else:
self.mythread.continuous = self.continuous
if self.button.isCheckable() and self.button.isChecked():
self.button.setText('Stop doing that')
self.contincheck.setDisabled(True)
self.mythread.start()
@QtCore.pyqtSlot(int)
def done(self, i):
print('done it', i)
@QtCore.pyqtSlot()
def thread_finished(self):
print('thread finished')
class MyThread(QtCore.QThread):
signal = QtCore.pyqtSignal(int)
def __init__(self, continuous=False, parent=None):
super(MyThread, self).__init__(parent)
self._stopped = True
self.continuous = continuous
self.i = 0
def __del__(self):
self.wait()
def stop(self):
self._stopped = True
def run(self):
self._stopped = False
while True:
self.signal.emit(self.i)
if self._stopped:
break
if self.continuous:
QtCore.QThread.sleep(2)
else:
break
if __name__ == '__main__':
app = QtCore.QCoreApplication.instance()
if app is None:
app = QtWidgets.QApplication(sys.argv)
mainGui = MyWindow()
mainGui.show()
app.aboutToQuit.connect(app.deleteLater)
app.exec_()
【讨论】:
太棒了!感谢您的宝贵时间!以上是关于Python - PyQt:重新启动已完成的线程的主要内容,如果未能解决你的问题,请参考以下文章