Python 如何阻止qt应用冻结主程序?

Python 如何阻止qt应用冻结主程序?,python,qt,user-interface,pyside,Python,Qt,User Interface,Pyside,例如: #!/usr/bin/env python3 import sys from PySide import QtCore, QtGui class Dialog(QtGui.QDialog): def __init__(self): QtGui.QDialog.__init__(self) button = QtGui.QPushButton("test") layout = QtGui.QVBoxLayout()

例如:

#!/usr/bin/env python3

import sys
from PySide import QtCore, QtGui

class Dialog(QtGui.QDialog):
    def __init__(self):
        QtGui.QDialog.__init__(self)
        button = QtGui.QPushButton("test")
        layout = QtGui.QVBoxLayout()
        layout.addWidget(button)
        self.setLayout(layout)

app = QtGui.QApplication(sys.argv)
toast = Dialog()
toast.show()
app.exec_()
print("App freezes the main process!")
在关闭对话框之前,不会执行最后一次打印功能

我正在编写一个脚本,它只使用qt来显示一些不需要用户交互的内容,因此我更希望gui代码在后台运行。

这是不可能的。国家:

尽管QObject是可重入的,但GUI类,尤其是QWidget及其所有子类,是不可重入的。它们只能从主线程使用。如前所述,还必须从该线程调用QCoreApplication::exec

重点矿山

另一方面,这表明事实并非如此:但PySide似乎坚持官方版本:

这可以通过以下代码示例进行验证:

import sys
import threading
from PySide import QtCore, QtGui

class Dialog(QtGui.QDialog):
    def __init__(self):
        QtGui.QDialog.__init__(self)
        button = QtGui.QPushButton("test")
        layout = QtGui.QVBoxLayout()
        layout.addWidget(button)
        self.setLayout(layout)

app = QtGui.QApplication(sys.argv)
toast = Dialog()
toast.show()

t = threading.Thread(target = lambda: app.exec_())
t.daemon = True
t.start()
print("App freezes the main process!")
input()
将生成以下输出:

App freezes the main process!
QApplication::exec: Must be called from the main thread
还有一次碰撞,在我的机器上。我还通过在另一个线程中创建应用程序验证了该选项-它可以工作,但在退出时崩溃


因此,解决方案似乎让Qt拥有主线程,并在单独的线程中组织处理。这应该不是一个真正的问题:如果你能很好地分离你的关注点,那么它在哪个线程上运行对你的控制台应用程序部分不会有任何影响。

我不确定PySide是否施加了任何限制,但下面是在C++中的实现方式:

在辅助线程中实例化QApplication。 在同一线程中创建对话框。 在同一线程中调用QDialog::exec或{QApplication::exec+QDialog::show}。 在退出应用程序之前,请确保辅助线程已完全关闭。 是的,Qt文档当前说只允许主线程。然而,在中没有任何内容禁止在辅助线程中创建QApplication,然后在该线程中为Windows和Linux使用GUI类。应更改文档


Mac OS X则不同——Cocoa框架只允许在主线程中进行GUI操作。

您必须具备一些功能,使程序不会结束。在执行到脚本末尾后,您希望发生什么?而是让打印和其他任务同时在一个单独的线程中执行,但是要考虑,是否真的需要一个单独的线程。在使用事件驱动框架时,这是一个常见的误解。我更喜欢为gui部分创建一个线程,让它在后台运行,因为在这种情况下,主要的逻辑和兴趣不在gui中。它有点像一个通知气泡,你让它弹出,然后设置计时器让它消失,回到主要的工作上,兴趣是无关紧要的。代码在哪个线程上运行的事实并不会使它在您的实现中变得不那么重要或不那么公开。事实上,这部分甚至不应该知道它在哪个线程上运行——请看我的答案。它崩溃是因为您在一个线程中实例化了QApplication,但在另一个线程中调用了它的方法exec。您不能这样做,因为QApplication不是线程安全的。您必须在辅助线程中实例化QApplication,然后在同一线程中调用exec。@JKSH我也尝试过:我还通过在另一个线程中创建应用程序验证了该选项-它可以工作,但在退出时崩溃。