为什么 input() 会导致 "QCoreApplication::exec: The event loop is already running"?
Why does input() cause "QCoreApplication::exec: The event loop is already running"?
我 运行 遇到了这个 QCoreApplication 问题,在 QObject 在 QThread 内完成执行后调用 input() 会导致无限循环打印到控制台 "QCoreApplication::exec: The event loop is already running"。
在代码中,我创建了一个通用的 worker 作为 QObject,将其移动到 QThread(使用 QThread 的认可方式,而不是 subclassing 它)然后执行另一个 QObject 的(Master class) 通用工作器中的函数。只要我在执行 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()
在您的示例中 input
没有真正的问题。在 done()
中按下回车后,控件将 return 进入事件循环,然后等待进一步的用户交互 - 这是正常和预期的行为。
你没有说清楚你希望在那之后发生什么。但是如果你想让程序退出,就这样做:
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()
,您将看到所有三个都在 主线程中执行 .这是因为您在 将 worker 移动到另一个线程之前连接了 thread.start
信号 。解决此问题的最佳(即最容易维护的)方法是始终在跨线程连接的任何插槽上使用 @pyqtSlot
装饰器——因为这样一来,何时建立信号连接就无关紧要了。 (有关此问题的更完整解释,请参阅 this answer)。
我 运行 遇到了这个 QCoreApplication 问题,在 QObject 在 QThread 内完成执行后调用 input() 会导致无限循环打印到控制台 "QCoreApplication::exec: The event loop is already running"。
在代码中,我创建了一个通用的 worker 作为 QObject,将其移动到 QThread(使用 QThread 的认可方式,而不是 subclassing 它)然后执行另一个 QObject 的(Master class) 通用工作器中的函数。只要我在执行 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()
在您的示例中 input
没有真正的问题。在 done()
中按下回车后,控件将 return 进入事件循环,然后等待进一步的用户交互 - 这是正常和预期的行为。
你没有说清楚你希望在那之后发生什么。但是如果你想让程序退出,就这样做:
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()
,您将看到所有三个都在 主线程中执行 .这是因为您在 将 worker 移动到另一个线程之前连接了 thread.start
信号 。解决此问题的最佳(即最容易维护的)方法是始终在跨线程连接的任何插槽上使用 @pyqtSlot
装饰器——因为这样一来,何时建立信号连接就无关紧要了。 (有关此问题的更完整解释,请参阅 this answer)。