QtGui.QApplication 和 QtCore.QCoreApplication 的区别

Posted

技术标签:

【中文标题】QtGui.QApplication 和 QtCore.QCoreApplication 的区别【英文标题】:Difference between QtGui.QApplication and QtCore.QCoreApplication 【发布时间】:2016-04-11 19:33:00 【问题描述】:

大家知道QtGui是用来给GUI程序创建界面的,QtCore是给非GUI程序用的,实际上是在界面下工作的。但是要获取正在运行的应用程序的实例,我发现我们可以使用 QtCore 和 QtGui 来返回当前运行的实例,使用 QtCore.QCoreApplicationQtGui.QApplication

那么使用它们返回的实例有什么区别呢? 他们指的是同一件事吗?

【问题讨论】:

【参考方案1】:

您可以使用shiboken 模块来检查实际情况:

>>> import shiboken
>>> from PySide import QtCore, QtGui
>>> app = QtGui.QApplication([])
>>> app
<PySide.QtGui.QApplication object at 0x7fc6031c98c8>
>>> print(shiboken.dump(app))
C++ address....... PySide.QtGui.QApplication/0x11446c0
hasOwnership...... 0
containsCppWrapper 1
validCppObject.... 1
wasCreatedByPython 1

>>> print(shiboken.dump(QtGui.QApplication.instance()))
C++ address....... PySide.QtGui.QApplication/0x11446c0
hasOwnership...... 0
containsCppWrapper 1
validCppObject.... 1
wasCreatedByPython 1

>>> print(shiboken.dump(QtCore.QCoreApplication.instance()))
C++ address....... PySide.QtGui.QApplication/0x11446c0
hasOwnership...... 0
containsCppWrapper 1
validCppObject.... 1
wasCreatedByPython 1

>>> print(shiboken.dump(QtGui.qApp))
C++ address....... PySide.QtGui.QApplication/0x11446c0
hasOwnership...... 0
containsCppWrapper 1
validCppObject.... 1
wasCreatedByPython 1

如您所见,每次都引用相同的底层 C++ 对象。如果您创建了QCoreApplication,则每次也会引用相同的QCoreApplication

这里的意图是应该只有一个应用程序对象。但是 Qt 类并不是真正的单例。因此,如果您尝试创建另一个实例,PySide 会选择引发错误:

>>> app2 = QtGui.QApplication([])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: A QApplication instance already exists.

但是,在 PyQt 中,没有什么可以阻止您创建多个实例,在 C++ 中也必须如此。据推测,这通常会导致未定义的行为。

sip.dump 与 PyQt 一起使用显示了其他一些重要的区别:

# NB: abbreviated output
>>> import sip
>>> from PyQt4 import QtCore, QtGui
>>> app = QtGui.QApplication([])
>>> sip.dump(app)
<PyQt4.QtGui.QApplication object at 0x7fc801a91678>
    Reference count: 3
    Address of wrapped object: 0x25190e0
    Created by: Python
    To be destroyed by: Python
>>> sip.dump(QtCore.QCoreApplication.instance())
<PyQt4.QtGui.QApplication object at 0x7fc801a91678>
    Reference count: 3
    Address of wrapped object: 0x25190e0
    Created by: Python
    To be destroyed by: Python
>>> sip.dump(QtGui.QApplication.instance())
<PyQt4.QtGui.QApplication object at 0x7fc801a91678>
    Reference count: 3
    Address of wrapped object: 0x25190e0
    Created by: Python
    To be destroyed by: Python
>>> sip.dump(QtGui.qApp)
<PyQt4.QtGui.QApplication object at 0x7fc801a91558>
    Reference count: 3
    Address of wrapped object: 0x25190e0
    Created by: C/C++
    To be destroyed by: C/C++

请注意,与 PySide 不同,qApp 实例是由 C++ 而不是 Python 创建的,并且 PyQt 包装器不一样。如果您决定创建自己的QApplication 子类,请记住这一点,因为qApp 将直接忽略它!如果您希望qApp 引用您自己的子类,则需要显式设置它,如下所示:

myapp = MyCustomApplication(sys.argv)
QtGui.qApp = myapp

在 PySide 中,不需要这个小技巧。

【讨论】:

【参考方案2】:

没有区别,因为QApplication 中的instance() 方法继承自QCoreApplication。您也可以如下演示:

>>> from PyQt4.QtCore import QCoreApplication
>>> from PyQt4.QtGui import QApplication
>>> a = QApplication([])
>>> a
<PyQt4.QtGui.QApplication object at 0x02A75620>
>>> QApplication.instance()
<PyQt4.QtGui.QApplication object at 0x02A75620>
>>> QCoreApplication.instance()
<PyQt4.QtGui.QApplication object at 0x02A75620>

>>> b = QCoreApplication([])
>>> b
<PyQt4.QtCore.QCoreApplication object at 0x02A75670>
>>> QCoreApplication.instance()
<PyQt4.QtCore.QCoreApplication object at 0x02A75670>
>>> QApplication.instance()
<PyQt4.QtCore.QCoreApplication object at 0x02A75670>

请注意,无论您使用哪个类访问实例,PyQt 都会正确地对对象进行类型转换。在 C++ 中,您需要自己进行这种类型转换。

【讨论】:

instance() 方法存在于两个类中,因为 QApplication 继承自 QCoreApplication。无论哪种情况,您都在调用相同的方法,该方法返回您将应用程序实例化为的任何内容。当然,在 C++ 中,您可能需要对返回值进行类型转换... @user3419537 你是对的。我有点假设他们会覆盖它以返回您从中调用它的类的正确类型,但我想没有意义(假设您甚至可以在 C++ 中做到这一点?) 谢谢.. 简单明了

以上是关于QtGui.QApplication 和 QtCore.QCoreApplication 的区别的主要内容,如果未能解决你的问题,请参考以下文章

QApplication构造函数段错误

PyQt4(简单布局)

“QApplication app(argc, argv)”想做啥?

PyQt4(简单界面)

使用信号弹屏

如何在 QTextBrowser 中居中选定文本