当前位置: 动力学知识库 > 问答 > 编程问答 >

python - Why does input() cause "QCoreApplication::exec: The event loop is already running"?

问题描述:

I have run into this QCoreApplication problem where invoking input() after a QObject finishes executing inside a QThread causes an infinite loop printing to the console "QCoreApplication::exec: The event loop is already running".

In the code I create a generic worker as a QObject, move it into a QThread (the sanctioned way to use QThread, instead of subclassing it) and then execute another QObject's (Master class) function inside the generic worker. Everything works fine as long as I don't call input() after the Master has been executed. Note that the problem occurs also if I execute a function directly in the worker (not a Master instance's function).

Here is the sample code to reproduce the problem:

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()

网友答案:

There is no real problem with input in your example. After pressing enter in done(), control will return to the event-loop and then wait for further user interaction - which is the normal and expected behaviour.

You don't make it clear what you expect to happen after that. But if you want the program to quit, just do this:

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

The Qt warning message is harmless, but it can be removed like this:

def main():
    from PyQt4.QtCore import pyqtRemoveInputHook
    pyqtRemoveInputHook()

    app = QCoreApplication(sys.argv)
    ...

The only real problem in your example is the threading implementation. If you add the line print(QThread.currentThread()) to Worker.run(), Master.do() and main(), you will see that all three are executed in the main thread. This is because you connected the thread.start signal before moving the worker to the other thread. The best (i.e. most easily maintainable) way to fix this issue to always use the @pyqtSlot decorator on any slots that are connected across threads - because then it won't matter when the signal connections are made. (See this answer for a more complete explanation of this issue).

分享给朋友:
您可能感兴趣的文章:
随机阅读: