2013-12-09 4 views
1

, когда кнопка нажата, следующий код начнет работать (вызывается из основного (GUI) потока), то пользовательский интерфейс стал замороженподпроцесс причиной пользовательского интерфейса, чтобы заморозить

def on_pushButton_clicked(self): 
     subprocess.call([r'C:\Program Files\ffmpeg-20131122-git-fb7d70c-win32-static\bin\ffmpeg', '-f', 'concat', '-i','mylist.txt', '-c', 'copy', 'output.mp4']) 

кто-нибудь может объяснить, почему? Subprocess() сам по себе не может работать асинхронно?

+0

Как @falsetu сказал использовать POPEN вы можете увидеть пример [здесь] (http://stackoverflow.com/a/20451375/1982962) –

+0

@ Kobi K, что мне делать, если я хочу знать, когда процесс будет завершен? – iMath

+0

'Popen.communicate()' wait's для завершения процесса, когда это будет сделано, следующая строка будет предварительно сформирована 'stdOutValue, stdErrValue = communicationRes', и тем самым вы получите stdout и ошибку. –

ответ

0

subprocess.call ожидает завершения субпроцесса. Вместо этого используйте subprocess.Popen.

def on_pushButton_clicked(self): 
    subprocess.Popen([r'C:\Program Files\ffmpeg-20131122-git-fb7d70c-win32-static\bin\ffmpeg', '-f', 'concat', '-i','mylist.txt', '-c', 'copy', 'output.mp4']) 
+0

, что мне делать, если я хочу знать, когда процесс будет завершен? – iMath

+0

@ user1485853, 'subprocess.Popen' возвращает объект« Popen »; Сохраните его где-нибудь. затем используйте метод ['subprocess.Popen.poll'] (http://docs.python.org/2/library/subprocess.html#subprocess.Popen.poll), чтобы проверить, завершен ли процесс. (Он возвращает 'None', если процесс все еще работает. Возвращает статус возврата в противном случае) – falsetru

+0

, поэтому мне нужно постоянно проверять, правильно? – iMath

0

Как уже сказал, subprocess.call будет ждать, пока команда завершена.

Но, учитывая, что вы используете PyQt, лучше использовать QProcess, так как это позволит вам использовать сигналы и события, чтобы поддерживать графический интерфейс.

Есть несколько вопросов, о которых стоит подумать.

Во-первых, команда ffmpeg будет висеть, если выходной файл уже существует, потому что по умолчанию он будет запрашивать у пользователя разрешение на перезапись. Поэтому было бы неплохо добавить флаг -y или -n, чтобы справиться с этим.

Во-вторых, команда может также зависать по какой-то неожиданной причине. Поэтому вы должны, вероятно, дать пользователю возможность принудительно убить процесс.

И наконец, что должно произойти, если пользователь попытается закрыть приложение до завершения команды? Вероятно, вам нужно будет обработать closeEvent главного окна, чтобы справиться с этим.

Демонстрационная ниже сценарий показывает некоторые возможные способы обработки вышеуказанных вопросов:

from PyQt4 import QtCore, QtGui 

class Window(QtGui.QWidget): 
    def __init__(self): 
     QtGui.QWidget.__init__(self) 
     layout = QtGui.QVBoxLayout(self) 
     self.label = QtGui.QLabel('Elapsed: 0', self) 
     layout.addWidget(self.label) 
     self.buttonStart = QtGui.QPushButton('Start', self) 
     self.buttonStart.clicked.connect(self.handleButtonStart) 
     layout.addWidget(self.buttonStart) 
     self.buttonStop = QtGui.QPushButton('Stop', self) 
     self.buttonStop.setDisabled(True) 
     self.buttonStop.clicked.connect(self.handleButtonStop) 
     layout.addWidget(self.buttonStop) 
     self._process = QtCore.QProcess(self) 
     self._process.started.connect(self.handleStarted) 
     self._process.finished.connect(self.handleFinished) 
     self._process.error.connect(self.handleError) 
     self._time = QtCore.QTime() 
     self._timer = QtCore.QTimer(self) 
     self._timer.timeout.connect(self.handleTimeout) 

    def closeEvent(self, event): 
     if self._timer.isActive(): 
      event.ignore() 
     else: 
      QtGui.QWidget.closeEvent(self, event) 

    def handleButtonStart(self): 
     self._running = True 
     self._process.start('ffmpeg', [ 
      '-f', 'concat', '-i', 'input.txt', 
      '-c', 'copy', '-y', 'output.mp4', 
      ], QtCore.QIODevice.ReadOnly) 

    def handleTimeout(self): 
     self.label.setText(
      'Elapsed: %.*f' % (2, self._time.elapsed()/1000.0)) 

    def handleButtonStop(self): 
     if self._timer.isActive(): 
      self._process.close() 

    def handleStarted(self): 
     self.buttonStart.setDisabled(True) 
     self.buttonStop.setDisabled(False) 
     self._time.start() 
     self._timer.start(50) 

    def handleFinished(self): 
     self._timer.stop() 
     self.buttonStart.setDisabled(False) 
     self.buttonStop.setDisabled(True) 

    def handleError(self, error): 
     if error == QtCore.QProcess.CrashExit: 
      print('Process killed') 
     else: 
      print(self._process.errorString()) 

if __name__ == '__main__': 

    import sys 
    app = QtGui.QApplication(sys.argv) 
    window = Window() 
    window.setGeometry(500, 300, 200, 100) 
    window.show() 
    sys.exit(app.exec_()) 
+0

, почему shoud мы иногда вызываем qApp.processEvents()? – iMath

+0

Я тестировал, что даже закрываю приложение, но команда ffmpeg по-прежнему работает в фоновом режиме до тех пор, пока не закончится, можете ли вы объяснить, почему? Возможно, мы можем зависеть от этой функции, поэтому нет необходимости обрабатывать closeEvent. – iMath

+0

@ пользователь1485853. Вы правы - строка 'qApp.processEvents()' была из более раннего редактирования и должна была быть удалена (теперь она исчезла). – ekhumoro

Смежные вопросы