【问题标题】:QQmlPropertyMap Insert; Mysteriously Inserting None, or Removing Other ValuesQQmlPropertyMap 插入;神秘地插入无或删除其他值
【发布时间】:2020-06-29 15:53:16
【问题描述】:

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

【问题讨论】:

    标签: python qt qml pyside2


    【解决方案1】:

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

    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
    

    【讨论】:

    • 我本来希望属性映射对象自然地保留对其值的引用,但最后一点可以解决问题 - 我猜当 Python 框架是 C++ 的包装器时,会发生这种不直观的事情框架。
    猜你喜欢
    • 1970-01-01
    • 2020-11-04
    • 2011-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-21
    • 2014-09-09
    相关资源
    最近更新 更多