如何阻止qt app冻结主程序?

时间:2014-11-12 15:26:05

标签: 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()
        layout.addWidget(button)
        self.setLayout(layout)

app = QtGui.QApplication(sys.argv)
toast = Dialog()
toast.show()
app.exec_()
print("App freezes the main process!")

在关闭对话框之前,不会执行最后一个print()函数。

我正在制作一个只使用qt显示一些不需要用户交互的内容的脚本,所以我更希望gui代码在后台运行。

2 个答案:

答案 0 :(得分:2)

这是不可能的。 Qt documentation州:

  

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

(强调我的)

另一方面,

This answer建议实际上这不是真的:)但似乎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

(崩溃,在我的机器上)。我还验证了在另一个线程中创建 app的选项 - 它可以工作,但在退出时崩溃。


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

答案 1 :(得分:1)

我不确定PySide是否会施加任何限制,但这里是用C ++完成的:

  1. 在辅助线程中实例化QApplication。
  2. 在同一个帖子中创建对话框。
  3. 在同一个帖子中调用QDialog :: exec()或{QApplication :: exec()加QDialog :: show()}。
  4. 在退出应用程序之前,请确保您的辅助线程已完全关闭。

  5. 是的,Qt文档目前说只允许主线程。但是,the Qt source code中没有任何内容禁止在辅助线程中创建QApplication,然后在该线程中使用GUI类(对于Windows和Linux)。文档应该更改。

    Mac OS X虽然不同 - 但Cocoa框架只允许主线程中的GUI操作。