Saltar al contenido

Cómo detener un QThread desde la GUI

Si encuentras algún problema con tu código o trabajo, recuerda probar siempre en un ambiente de testing antes aplicar el código al trabajo final.

Solución:

Sé que fue hace mucho tiempo, pero me encontré con el mismo problema.

También he estado buscando una manera apropiada de hacer esto. Finalmente fue fácil. Al salir de la aplicación, la tarea debe detenerse y el subproceso debe detenerse llamando a su método de salida. Vea el método stop_thread en la parte inferior. Y tienes que esperar a que termine el hilo. De lo contrario obtendrá QThread: Destruido mientras el hilo aún se está ejecutando ‘mensaje al salir.

(También cambié mi código para usar 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_())

Descubrí que mi pregunta original era en realidad dos preguntas en una: para detener un hilo secundario del principal, necesitas dos cosas:

  1. Ser capaz de comunicarse desde el hilo principal. abajo al hilo secundario

  2. Enviar la señal adecuada para detener el hilo.

No he podido resolver (2), pero descubrí cómo resolver (1), lo que me dio una solución a mi problema original. En lugar de detener la hilopuedo detener el hilo Procesando (la longRunning() método)

El problema es que un subproceso secundario solo puede responder a las señales si ejecuta su propio ciclo de eventos. Un Qthread regular (que es lo que usó mi código) no lo hace. Sin embargo, es bastante fácil crear una subclase de QThread a tal efecto:

class MyThread(QThread):
    def run(self):
        self.exec_()

y usado self.simulThread = MyThread() en mi código en lugar del original self.simulThread = Qthread(). Esto garantiza que el subproceso secundario ejecute un bucle de eventos. Sin embargo, eso no fue suficiente. Él longRunning() El método necesita tener la oportunidad de procesar realmente el evento que proviene del hilo principal. Con la ayuda de esta respuesta SO, descubrí que la simple adición de un QApplication.processEvent() en el longRunning() El método le dio al subproceso secundario tal oportunidad. Ahora puedo detener el Procesando llevado a cabo en el subproceso secundario, aunque no he descubierto cómo detener el subproceso en sí.

Para concluir. Mi método longRunning ahora se ve así:

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

y mi subproceso GUI tiene estas tres líneas que hacen el trabajo (además de la subclase QThread mencionada anteriormente):

    self.simulThread = MyThread()
    self.simulRunner.moveToThread(self.simulThread)
    self.stopButton.clicked.connect(self.simulRunner.stop)

¡Los comentarios son bienvenidos!

Si te ha sido de ayuda este post, sería de mucha ayuda si lo compartieras con el resto juniors así contrubuyes a extender nuestro contenido.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *