Python-PyQt:重新启动已完成的线程

Python-PyQt:重新启动已完成的线程,python,multithreading,pyqt,pyqt5,qthread,Python,Multithreading,Pyqt,Pyqt5,Qthread,我有一个pyqt接口,如果按下按钮,它会启动一个QThread。线程运行,当它完成后,我可以再次启动它,到目前为止没有问题。 我现在为线程的连续操作添加了一个复选框。如果选中复选框,则按钮保持按下状态,必须再次按下按钮以停止螺纹 显然,停止后,线程已正确完成(也使用isRunning()方法进行检查),但如果我尝试在连续操作中再次启动它,程序将崩溃。如果我在关闭continuous operation的情况下重新启动它,则不会发生这种情况,但在这种情况下,线程会启动和停止两次 如何解释这种行为?

我有一个pyqt接口,如果按下按钮,它会启动一个QThread。线程运行,当它完成后,我可以再次启动它,到目前为止没有问题。 我现在为线程的连续操作添加了一个复选框。如果选中复选框,则按钮保持按下状态,必须再次按下按钮以停止螺纹

显然,停止后,线程已正确完成(也使用
isRunning()
方法进行检查),但如果我尝试在连续操作中再次启动它,程序将崩溃。如果我在关闭continuous operation的情况下重新启动它,则不会发生这种情况,但在这种情况下,线程会启动和停止两次

如何解释这种行为?有没有办法让它按预期工作

例如:

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_()

问题是您正在创建一个新线程,而不是重用现有线程,在下面的示例中,我将向您展示如何正确执行该操作:

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_()

伟大的谢谢你的时间!