QML中值的双重初始化

时间:2017-05-10 12:45:30

标签: qt qml qtquick2 qt5.7

我有一个奇怪的问题,就是在一个大项目中的某个地方埋葬。到目前为止,我无法在 MCVE 中重现它,但只要我成功,我就会将其转入。

这是一个非常简单的行为。基本上我有QtObject属性,我用这样的初始值设置:

TestObj.qml

QtObject {
    id: root
    property int val1: { console.log('set val', root); return 42 }
    Component.onCompleted: console.log('Constructed Object', this)
}

!!! 通过此示例,我不会重现错误 !!!

我的项目中的输出现在是:

  

set val TestObj_QMLTYPE_44(0x33799fa8)
  set val TestObj_QMLTYPE_44(0x33799fa8)
  Constructed Object TestObj_QMLTYPE_44(0x33799fa8)

因此,尽管该对象仅创建一次,但初始属性赋值执行两次 由于我不知道,在哪里寻找罪魁祸首,我无法生成一个可重复的例子,但也许有人在相同的情况下偶然发现并找到了解决方案。

解决方案将是有益的,因为这个问题导致一些对象的多个实例化,我无法破坏。

1 个答案:

答案 0 :(得分:0)

  

Created Bug-Report: 也许他们找到了解决这个问题的方法,而不是黑客的解决方法

问题是循环引用:

循环引用在创建对象时会导致奇怪的行为。

<强> TestObj1.qml

import QtQuick 2.0
QtObject {
    property Item paps
    property int myVal: { console.log('myVal'); paps.val }
}

<强> TestObj2.qml

import QtQuick 2.0    
Item {
    id: root
    property int val: { console.log('set val', root); return 42 }
    Component.onCompleted: console.log('Constructed Object')

    TestObj1 {
        id: to1
        paps: root
    }
}

<强>结果:

  

qml: myVal
  的 qml: set val TestObj_QMLTYPE_4(0x2c0bafb0)
  的 qml: set val TestObj_QMLTYPE_4(0x2c0bafb0)
  qml: Constructed Object

probalbe的原因是,语句{console.log('set val', root); return 42 }尚未处理,当它已经全部分配给myVal时,因此该语句执行了两次。

虽然这在普通情况下没有问题,但只要我们在这些属性中没有动态创建的对象,就可能会出现问题。

<强> TestObj3.qml

import QtQuick 2.0

Item {
    id: root
    property QtObject obj: { console.log('set obj'); return objPrototype.createObject(root) }
    Component.onCompleted: console.log('Constructed Object', obj)

    TestObj4 {
        id: to1
        paps: root
    }

    Component {
        id: objPrototype
        QtObject {
            id: op
            Component.onCompleted: console.log('PropertyObject created', op)
        }
    }
}

<强> TestObj4.qml

import QtQuick 2.0
QtObject {
    property Item paps
    property QtObject myObj: paps.obj

    Component.onCompleted: console.log(myObj)
}

<强>结果:

  

qml: set obj
  的 qml: PropertyObject created QObject(0x2c124708)
  qml: set obj
  的 qml: PropertyObject created QObject(0x2c1246f8)
  qml: Constructed Object QObject(0x2c1246f8)
  qml: QObject(0x2c1246f8)

所以你可以看到,对象确实创建了两次。

有一些解决方法:

  1. 不要使用循环引用 - 但这样就可以了。
  2. 不要使用动态对象创建,因为它总是会产生问题 - 我可以创建对象,并使用property alias obj: myObjectIDproperty QtObject obj: myObjectID。这有缺点,如果组件可重用,用户无法替换该对象或仍然创建对象,浪费内存。
  3. 如果属性仍为空(未被可重用组件的用户覆盖),则在Component.onCompleted中分配属性。这有缺点,即对象不可用,uppon将出现创建和大量Can't read property ... of null错误。他们希望不会破坏应用程序。
  4. 创建一个讨厌的绑定循环写:property QtObject obj: (obj ? obj : objPrototype.createObject(root))。它会发出警告,但来吧。它只是一个绑定循环,将被检测到并被破坏。
  5. 这些解决方法没什么好看的,但可能是可用的东西。