首页 > 解决方案 > QQmlPropertyMap 插入;神秘地插入无或删除其他值

问题描述

我在 PySide2 和 QML 中工作,而 QQmlPropertyList 正在做两件我觉得很奇怪的事情。

第一个是如果 QObject 是在同一语句中创建的,则将其分配为值不起作用:

from PySide2.QtCore import QObject
from PySide2.QtQml import QQmlPropertyMap

qmap = QQmlPropertyMap()
qmap.insert('test_key', QObject())
print(qmap.value('test_key'))

输出:

None

也许这与初始化 QObject 的时间有关?可以通过先将其分配给变量来修复它:

qmap = QQmlPropertyMap()

obj = QObject()
qmap.insert('test_key', obj)

print(qmap.value('test_key'))
<PySide2.QtCore.QObject(0x7fe8f26b5eb0) at 0x107075ec0>

但它变得陌生。忍受我。分配两个 QObjects 工作:

qmap = QQmlPropertyMap()

obj = QObject()
qmap.insert('test_key', obj)

obj2 = QObject()
qmap.insert('test_key2', obj2)

print(qmap.value('test_key'))
print(qmap.value('test_key2'))
<PySide2.QtCore.QObject(0x7f85f7f269e0) at 0x10d32b080>
<PySide2.QtCore.QObject(0x7f85f7f26b70) at 0x10d32b100>

我什至可以将同一个对象分配给多个键:

qmap = QQmlPropertyMap()

obj = QObject()
qmap.insert('test_key', obj)
qmap.insert('test_key2', obj)

print(qmap.value('test_key'))
print(qmap.value('test_key2'))
<PySide2.QtCore.QObject(0x7fde37d7d9d0) at 0x105cdc140>
<PySide2.QtCore.QObject(0x7fde37d7d9d0) at 0x105cdc140>

但是,如果我为两个不同的对象重用相同的变量名,第一个键的值会以某种方式被删除:

qmap = QQmlPropertyMap()

obj = QObject()
qmap.insert('test_key', obj)

obj = QObject()
qmap.insert('test_key2', obj)

print(qmap.value('test_key'))
print(qmap.value('test_key2'))
None
<PySide2.QtCore.QObject(0x7fcecaf072f0) at 0x111ba60c0>

怎么会这样?PySide 是否对运行时变量名称进行了某种隐藏的魔法?在这个例子中,这是微不足道的,但它在我的代码中导致了一个难以隔离的错误,我想更好地理解这一点。

标签: pythonqtqmlpyside2

解决方案


当您创建一个对象并为其分配相同的变量时,前一个对象被销毁,可以通过以下测试观察到:

class Foo:
    def __del__(self):
        print("destroyed")

print("before creating Foo object: 1")
foo = Foo()
print("after creating Foo object: 1")
print("before creating Foo object: 2")
foo = Foo()
print("after creating Foo object: 2")

输出

before creating Foo object: 1
after creating Foo object: 1
before creating Foo object: 2
destroyed
after creating Foo object: 2
destroyed

正如你所看到的,当第二个对象被分配给同一个变量时,第一个被销毁的被调用。所以这不是 PySide2 的魔力,而是 python 的魔力,同样可以用被破坏的信号来验证。

from PySide2.QtCore import QObject


print("before creating QObject object: 1")
qobject = QObject()
qobject.destroyed.connect(lambda _id=id(qobject): print("destroyed1: ", _id))
print("after creating QObject object: 1")
print("before creating QObject object: 2")
qobject = QObject()
qobject.destroyed.connect(lambda _id=id(qobject): print("destroyed2: ", _id))
print("after creating QObject object: 2")

输出:

before creating QObject object: 1
after creating QObject object: 1
before creating QObject object: 2
destroyed1:  <PySide2.QtCore.QObject(0x562c1b6ee2f0) at 0x7f4a1faece40>
after creating QObject object: 2

如果你不希望这个问题发生,那么使用 Qt 的超能力,你可以将对象作为“qmap”的父级传递,因此所有权将由 QObject 持有,它将不再由 python 处理:

from PySide2.QtCore import QObject
from PySide2.QtQml import QQmlPropertyMap


qmap = QQmlPropertyMap()

obj = QObject(qmap)
qmap.insert("test_key", obj)

obj = QObject(qmap)
qmap.insert("test_key2", obj)

print(qmap.value("test_key"))
print(qmap.value("test_key2"))

输出:

<PySide2.QtCore.QObject(0x559629d1e230) at 0x7fef951f01c0>
<PySide2.QtCore.QObject(0x559629d1eae0) at 0x7fef951f0240>

更新:

为了更好地理解,我们必须知道 PySide2 的 QObject(也适用于 PyQt5)是 Qt 的 QObject 的一个包装器,也就是说,它类似于:

class PyQObject:
    def __init__(self, *args):
        self._qobject_cpp = CPPQObject(*args)
        # ...
    def __del__(self):
        delete self._qobject_cpp

推荐阅读