【问题标题】:Why does input() cause "QCoreApplication::exec: The event loop is already running"?为什么 input() 会导致“QCoreApplication::exec: 事件循环已经在运行”?
【发布时间】:2016-10-21 13:18:50
【问题描述】:

我遇到了这个 QCoreApplication 问题,在 QObject 在 QThread 内完成执行后调用 input() 会导致无限循环打印到控制台“QCoreApplication::exec: 事件循环已在运行”。

在代码中,我创建了一个通用工作者作为 QObject,将其移动到 QThread(使用 QThread 的认可方式,而不是对其进行子类化),然后在通用工作者中执行另一个 QObject(主类)函数。只要我在执行 Master 后不调用 input() ,一切都可以正常工作。请注意,如果我直接在 worker 中执行函数(不是 Master 实例的函数),也会出现问题。

这里是重现问题的示例代码:

import sys
from PyQt4.QtCore import QCoreApplication, QObject, QThread, pyqtSignal, pyqtSlot


class Worker(QObject):
    """
    Generic worker.
    """
    start = pyqtSignal(str)
    finished = pyqtSignal()

    def __init__(self, function):
        QObject.__init__(self)
        self._function = function
        self.start.connect(self.run)

    def run(self):
        self._function()
        self.finished.emit()


class Master(QObject):
    """
    An object that will use the worker class.
    """
    finished = pyqtSignal()

    def __init__(self):
        QObject.__init__(self)

    @pyqtSlot()
    def do(self):
        print("Do what?")
        self.finished.emit()


def done():
    # FIXME This will cause an infinite loop printing to the console:
    # "QCoreApplication::exec: The event loop is already running"
    input("Enter your answer: ")


def main():
    app = QCoreApplication(sys.argv)

    master = Master()
    worker = Worker(master.do)
    master.finished.connect(done)

    thread = QThread()
    thread.started.connect(worker.run)
    worker.moveToThread(thread)

    # Terminating thread gracefully, or so.
    worker.finished.connect(thread.quit)
    worker.finished.connect(worker.deleteLater)
    thread.finished.connect(thread.deleteLater)

    thread.start()

    sys.exit(app.exec_())


if __name__ == "__main__":
    main()

【问题讨论】:

    标签: python multithreading input pyqt4 qcoreapplication


    【解决方案1】:

    在您的示例中,input 没有真正的问题。在done() 中按回车后,控制将返回事件循环,然后等待进一步的用户交互 - 这是正常和预期的行为。

    你没有明确说明你期望在那之后发生什么。但是,如果您希望程序退出,只需执行以下操作:

    def done():
        input("Enter your answer: ")
        QCoreApplication.quit()
    

    Qt 警告信息是无害的,但可以这样删除:

    def main():
        from PyQt4.QtCore import pyqtRemoveInputHook
        pyqtRemoveInputHook()
    
        app = QCoreApplication(sys.argv)
        ...
    

    您的示例中唯一真正的问题是线程实现。如果将print(QThread.currentThread()) 行添加到Worker.run()Master.do()main(),您将看到所有三个都在主线程 中执行。这是因为您在将工作线程移动到另一个线程之前连接了thread.start 信号。解决此问题的最佳(即最易于维护)的方法是始终在跨线程连接的任何插槽上使用 @pyqtSlot 装饰器 - 因为这样何时建立信号连接就无关紧要了。 (有关此问题的更完整说明,请参阅this answer)。

    【讨论】:

    • 太棒了!我用你的回答解决了 2 个问题。非常感谢。
    猜你喜欢
    • 1970-01-01
    • 2023-01-02
    • 1970-01-01
    • 1970-01-01
    • 2015-09-07
    • 2019-11-30
    • 2015-01-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多