subprocess Popen blocking PyQt GUI

2019-01-15 12:05发布

问题:

I'm trying to build a simple gui for a video converter application called "HandBrake" using PyQt.

My problem is that when I choose a video file to convert, subprocess Popen starts handbrake application with the necessary args but while waiting for handbrake to finish the gui gets blocked so I can't do any changes. (Ex: I can't disable the pushButton nor change its text)

I'm not looking for a more complicated solution such as progressbar etc. but I'd like to simply disable the button and change its text while waiting for the program to finish converting.

How can I do such thing with python & pyqt?

def videoProcess():
    self.pushButton.setEnabled(0)
    self.pushButton.setText("Please Wait")
    command = "handbrake.exe -i somefile.wmv -o somefile.mp4"
    p = subprocess.Popen(str(command), shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    while 1:
        line = p.stdout.readline()
        if not line:
            self.pushButton.setEnabled(1)
            break

回答1:

Since you are in Qt land already you could do something like this:

from PyQt4.QtCore import QProcess

class YourClass(QObject):

    [...]

    def videoProcess(self):
        self.pushButton.setEnabled(0)
        self.pushButton.setText("Please Wait")
        command = "handbrake.exe"
        args =  ["-i", "somefile.wmv", "-o", "somefile.mp4"]
        process = QProcess(self)
        process.finished.connect(self.onFinished)
        process.startDetached(command, args)

    def onFinished(self, exitCode, exitStatus):
        self.pushButton.setEnabled(True)

    [...]

http://doc.qt.io/qt-5/qprocess.html



回答2:

If you don't care about the output anyway, you can use p.wait() to wait for the subproc to finish, but you still need to return control to the QT main loop, so you need to insert a thread somehow. The simplest solution would be something like:

import threading
def reenable():
    p.wait()
    self.pushButton.setEnabled(1)
t = threading.Thread(reenable)
t.run()

There are numerous unresolved issues with this. For example, is it permissible to call GUI actions from multiple thread? What about a timeout? But it should be enough to point you in the right direction.