单击该按钮时,以下代码开始运行(从主(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 :(得分: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'])
答案 1 :(得分:0)
正如其他人所说,subprocess.call
将等到命令完成。
但鉴于您使用的是PyQt,使用QProcess可能会更好,因为这样可以使用信号和事件来保持GUI的响应。
要考虑一些问题。
首先,如果输出文件已经存在,示例ffmpeg
命令将挂起,因为,通过deafult,它将提示用户允许覆盖。因此,最好添加-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_())