python qt user-interface pyqt subprocess

python - Cómo hacer cosas durante y después de un proceso secundario



qt user-interface (1)

p = subprocess.Popen(exe) no espera a que el programa finalice - regresa tan pronto como se inicia el exe .

p.communicate() espera a que finalice el proceso hijo y, por lo tanto, bloquea el hilo de la GUI (la GUI se congela hasta que el subproceso finaliza).

Para evitar el bloqueo de la GUI, puede verificar si p.poll() devuelve None para averiguar si el proceso p aún se está ejecutando. Por lo general, un marco de GUI proporciona una forma de configurar devoluciones de llamadas periódicas (por ejemplo, QTimer para Qt) - puede llamar a p.poll() allí. O ponga la llamada de bloqueo (como p.wait() ) en un hilo de fondo y notifique el hilo de la GUI al finalizar (emitir señal, generar un evento).

QProcess sugerido por @dano ya tiene incorporado el mecanismo de notificación (señal de finished ).

Como dijo @three_pineapples : no conectes la misma señal varias veces si no quieres que se llamen varias veces. No tiene sentido llamar a .start() en la misma instancia del proceso más de una vez:

def run(self): self.runButton.setEnabled(False) # call it first because # processes are not started instantly self.process = QtCore.QProcess(self) self.process.started.connect(self.onstart) # connect "start" signal self.process.finished.connect(self.onfinish) self.process.start(exe_path, args) # then start

Tengo un programa que llama a un subprograma. Mientras el subprograma se ejecuta con Popen, necesito que el botón de ejecución se desactive y el botón de detener para habilitarlo. Sin embargo, dado que Popen abre un nuevo proceso, las cosas que se supone que se imprimirán una vez que el programa haya terminado se imprimirán de inmediato. Intenté agregar self.p.communicate() después de Popen , pero la GUI se congelará hasta que el subprograma termine de ejecutarse, por lo tanto, el botón de detención no funcionará. Aquí está mi programa:

def gui(QtGui.QWidget): ... self.runButton = QtGui.QPushButton(''Run'') self.stopButton = QtGui.QPushButton(''Stop'') self.runButton.clicked.connect(self.run) self.stopButton.clicked.connect(self.kill) self.runButton.setEnabled(True) self.stopButton.setEnabled(False) def run(self): self.runButton.setEnabled(False) self.p = subprocess.Popen(sample.exe) #self.p.communicate() self.stopButton.setEnabled(True) print "Finish running" #without communicate() it will print out before .exe finish running def kill(self): self.p.kill() self.stopButton.setEnabled(False) print ''You have stop the program'' self.runButton.setEnabled(True)

Estoy usando Window7, Python 2.7, pyqt4. No tengo que usar el subproceso, todo lo que esté abierto y pueda matar al subprograma estará bien.

Gracias por adelantado.

Editar: Probado usando QProcess como dano sugerido. He agregado los siguientes códigos a mi programa:

def gui(QtCore.Widget): self.process = QtCore.QProcess(self) def run(self): self.process.start(exe_path) self.process.started.connect(self.onstart) self.process.finished.connect(self.onfinish) self.runButton.setEnabled(False) #self.p = subprocess.Popen(sample.exe) #removed #self.p.communicate() #removed def onstart (self): self.stopButton.setEnabled(True) self.runButton.setEnabled(False) print "Started/n" def onfinish (self): self.stopButton.setEnabled(False) self.runButton.setEnabled(True) print "Finish running/n" def kill(self): self.process.kill() #self.p.kill() #removed

Aquí está el resultado:

Haga clic en "Ejecutar" (salida cuando el subprograma termine de ejecutarse)

Finish running

Haga clic en "Ejecutar" por segunda vez

Started

Haga clic en "Parar"

Finish running Finish running

Haga clic en "Ejecutar" por tercera vez

Started Started

Haga clic en "Parar"

Finish running Finish running Finish running

Algo sucedió aquí.