1

给定以下代码

button = ...
process = QProcess()
button.clicked.connect(start_process)

def start_process():

    # Disable the button
    button.setEnabled(False)
    # This seems to have no effect (...)

    # This also has no effect, thus commented out.
    # QApplication.processEvents(QEventLoop.ExcludeUserInputEvents)

    # Execute the program in a blocking way
    process.execute('/usr/bin/libreoffice')
    # (...) as right now, while libreoffice is running and I click the button
    # no animation is taking place, but the click !! is getting registered !!
    # If I terminate libreoffice, these clicks are executed and this function is
    # called again for every click done.

    # When the process and all its children have terminated, enable the button again
    button.setEnabled(True)

我已经在代码中解释了我的问题。我认为这与主线程(gui线程)被process.execute(...)调用阻塞有关,而setEnabled(False)调用仍在队列中或其他东西中。

我想要达到的目标:

  1. 用户单击 Button -> Button 被禁用并启动 LibreOffice
  2. 在 LibreOffice 运行时,我的 GUI 被阻止并且未注册按钮的点击
  3. 用户退出 LibreOffice,我的 GUI 被解锁,并且再次启用按钮以再次启动 LibreOffice

最终可能会奏效的方法:

我没有使用 ,而是process.execute(...)使用process.start(...)并将start()信号挂钩到我自己的功能以禁用按钮和finished()信号以再次启用按钮?

最终起作用的是:

class C(QObject):
    """
    Host (Communicator) for all my signals
    """
    enableButton = QtCore.Signal()
    disableButton = QtCore.Signal()


class MainWindow(QtGui.QMainWindow):
    def __init__(self, program=None, c=None, parent=None):
        super(MainWindow, self).__init__(parent)
        self.ui = Ui_mainWindow()
        self.ui.setupUi(self)

        self.program = program
        self.c = c  # Reference to the C instance
        self.setupSignals()

    def setupSignals(self):
        self.ui.btnStart.clicked.connect(self.program.start) # Trigger button

        # Register for events from UI Thread
        self.c.enableButton.connect(self.button_enable)
        self.c.disableButton.connect(self.button_disable)

    def button_enable(self):
        self.ui.btnStart.setEnabled(True)

    def button_disable(self):
        self.ui.btnStart.setEnabled(False)


class Program(object):
    def __init__(self, c=None):
        self.c = c
        self.proc = QProcess()  # The process to run in the start method.
                                # needed here because its runs out of scope otherwise.

    def start(self):

        def _onStart():
            self.c.disableButton.emit()
            print("on Start")

        def _onFinish():
            self.c.enableButton.emit()
            print("on Finish")

        def _onError():
            print("on Error")

        self.proc.started.connect(_onStart)
        self.proc.finished.connect(_onFinish)
        self.proc.error.connect(_onError)
        self.proc.start('/usr/bin/libreoffice')  # Waits until process ends

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    c = C()

    program = Program(c=c)
    main_window = MainWindow(program=program, c=c)
    main_window.show()

    sys.exit(app.exec_())

我希望我没有把它剥离太多。如果您有任何疑问,请继续。

4

1 回答 1

5

你已经自己回答了你的问题:),所以我只是总结一下:

  • QProcess.execute(顺便说一句,它是静态的,所以在这种情况下不需要创建QProcess对象)启动子进程并等待子进程完成 - 当子进程正在运行时,调用进程被阻塞并且您的 UI 被冻结

  • 要达到您的要求,请使用QProcess.start()异步启动子进程,并将相应的信号started()finished(). 有关要考虑的一些详细信息,请参阅文档中的注释。

于 2013-04-04T07:09:51.690 回答