qApp 与 QApplication.instance()

2022-01-12 00:00:00 python pyqt pyqt5 instance qapplication

问题描述

使用 PyQt5,这两个都返回应用程序对象:

With PyQt5, both of these return the application object:

app = QtWidgets.QApplication.instance()
app = QtWidgets.qApp
for i in app.arguments()[1:]:
    ...

但是为什么print(QtWidgets.QApplication.instance() is QtWidgets.qApp) print False?

But why does print(QtWidgets.QApplication.instance() is QtWidgets.qApp) print False?


解决方案

QtWidgets.QApplication.instance()QtWidgets.qApp的区别在于后者是一个静态模块变量,必须在第一次导入模块时创建.这会导致以下最初令人困惑的行为:

The difference between QtWidgets.QApplication.instance() and QtWidgets.qApp is that the latter is a static module variable that must be created when the module is first imported. This results in the following initially baffling behaviour:

>>> from PyQt5 import QtWidgets
>>> inst = QtWidgets.QApplication.instance()
>>> qapp = QtWidgets.qApp
>>> (inst, qapp)
(None, <PyQt5.QtWidgets.QApplication object at 0x7ff3c8bd3948>)

因此,即使尚未创建 QApplication 对象,qApp 变量仍然指向 QApplication 实例.如果模块更像类,因此它们可以具有动态属性,那么 qApp 可能会像 QApplication.instance() 一样工作并最初返回 .但是因为它是静态的,所以它必须始终返回一个正确类型的对象,以便它以后可以引用与 QApplication.instance() 相同的底层 C++ 对象.

So even though no QApplication object has been created yet, the qApp variable still points to a QApplication instance. If modules were more like classes, so that they could have dynamic properties, it would be possible for qApp to work exactly like QApplication.instance() does and initially return None. But because it is static, it must always return an object of the correct type, so that it can later refer to the same underlying C++ object as QApplication.instance().

然而,重要的是要注意 qApp 最初只是一个 empty 包装器:

However, it's important to note that qApp is initially just an empty wrapper:

>>> qapp.objectName()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: wrapped C/C++ object of type QApplication has been deleted

一旦创建了 QApplication,它们都会指向同一个东西:

Once the QApplication is created, though, they will both point to the same thing:

>>> app = QtWidgets.QApplication([])
>>> app.setObjectName('foo')
>>> qapp.objectName()
'foo'

所以 (QtWidgets.QApplication.instance() is QtWidgets.qApp) 返回 False 的原因是,这两个对象是围绕相同底层的不同 python 包装器C++ 对象.

So the reason why (QtWidgets.QApplication.instance() is QtWidgets.qApp) returns False, is that the two objects are different python wrappers around the same underlying C++ object.

如果您需要创建自己的 QApplication 子类,但仍想使用 qApp,请务必注意这一点:

It's important to be aware of this point if you ever need to create your own sublass of QApplication, but still want to use qApp:

>>> from PyQt5 import QtWidgets
>>> class MyApp(QtWidgets.QApplication):
...     def hello(self): print('Hello World')
...
>>> myapp = MyApp([])
>>> myapp.hello()
Hello World
>>>
>>> QtWidgets.qApp
<PyQt5.QtWidgets.QApplication object at 0x7f5e42f40948>
>>> QtWidgets.qApp.hello()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'QApplication' object has no attribute 'hello'
>>>
>>> inst = QtWidgets.QApplication.instance()
>>> inst
<__main__.MyApp object at 0x7f5e42f409d8>
>>> inst.hello()
Hello World

解决这个问题的唯一方法是显式覆盖 qApp 模块变量(并且显然要确保在其他模块可以导入之前完成此操作):

The only way around this is to explicitly overwrite the qApp module variable (and obviously ensure that this is done before it can be imported by other modules):

>>> QtWidgets.qApp = myapp
>>> QtWidgets.qApp.hello()
Hello World

相关文章