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:
from PyQt4.QtCore import QCoreApplication, QObject, QThread, pyqtSignal, pyqtSlot
start = pyqtSignal(str)
finished = pyqtSignal()
def __init__(self, function):
self._function = function
An object that will use the worker class.
finished = pyqtSignal()
# FIXME This will cause an infinite loop printing to the console:
# "QCoreApplication::exec: The event loop is already running"
input("Enter your answer: ")
app = QCoreApplication(sys.argv)
master = Master()
worker = Worker(master.do)
thread = QThread()
# Terminating thread gracefully, or so.
if __name__ == "__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
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).