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í.