QML 属性 的依赖评估顺序

Order of QML property's dependency evaluation

我有一个 CustomQMLComponent。它有3个属性。 p3 依赖于 p1 和 p2。 p1 和 p2 在创建 CustomQMLComponent 的实例时设置。

问题:

  1. 在计算 p3 时,p1 和 p2 是否始终具有调用者设置的值。
  2. 推荐的设置p3的方法是什么,如下所示或注释语句中的?

CustomQMLComponent.qml:

Item {
    required property string p1
    property bool p2 : false
    property int p3: cppContextPropertyObj.slot(p1, p2)
    //Component.onCompleted: p3 = cppContextPropertyObj.slot(p1, p2)
}

main.qml:

CustomQMLComponent{
    p1: "my_string"
    p2: true
}

更新:

p1 和 p2 具有静态赋值,而 p3 具有绑定赋值。
根据这篇旧文章:https://www.kdab.com/qml-engine-internals-part-2-bindings/,静态值分配发生在创建阶段,绑定值分配发生在创建阶段结束时。

案例 1:

CustomQMLComponent{}

在这种情况下,根据上述文章,p1 和 p2 值在设置 p3 值时设置。

案例二:

CustomQMLComponent{
    p1: "my_string"
    p2: true
}

在这种情况下会发生什么?

从更一般的意义上讲,在创建组件的实例时设置组件的属性会发生什么?属性是否使用默认值初始化,然后被新实例的值覆盖?或者,属性仅使用 default/new 值初始化一次。

这一行不仅仅是一个赋值,它也是一个绑定:

property int p3: cppContextPropertyObj.slot(p1, p2)

这意味着每当其中引用的 属性(在本例中为 p1 和 p2)发生变化时,它都会被重新评估 - 即它们的 *Changed 事件被发出。

因此,只要依赖于 p3 的任何东西可以多次处理 p3 更改值并且 slot 方法可以处理 p1 和 p2 的各种值,这并不重要。

要查看在这种特殊情况下发生的确切顺序,请添加 onP1Changed、onP2Changed 和 onP3Changed 事件处理程序并将它们的值记录到控制台。

来自 Qt 支持的响应:

根据这篇旧文章:https://www.kdab.com/qml-engine-internals-part-2-bindings/,静态值分配发生在创建阶段,绑定值分配发生在创建阶段结束。

That is how it should be, literals first, then functions. But it is not actually documented so in theory it could change. This is also only true for simple literal assignments. Anything even slightly hinting about complexity makes QML engine postpone them together with all those needing the evaluation. For example it happens if you wrap the value with {} like this: p2: {true}

案例一:

CustomQMLComponent{}

在这种情况下,根据上述文章,p1 和 p2 值在设置 p3 值时设置。

The order in which these "static" properties are set is undefined and also the order in which more complex expressions are done are undefined. So it is best to avoid making assumptions about the order.

案例二:

CustomQMLComponent{
    p1: "my_string"
    p2: true
}

在这种情况下会发生什么?

从更一般的意义上讲,在创建组件实例时设置组件的属性会发生什么?属性是否使用默认值初始化,然后被新实例的值覆盖?或者,属性仅使用 default/new 值初始化一次。

Just once. Although the properties do of course have some default value before the value in QML is assigned. The initial value set in constructor of a C++ class, or in case of QML defined property, default constructed value of the type (empty string, 0, false or null in case it is QObject* type).

And why this could be important is because something like onXXXChanged signals are handled immediately when they occur and thus it could be ran before all those "static" assignment are done. Consider for example:

onP1Changed: if (p2) {...} else {...}

QML engine does not know that there is some dependency to p2 on p1 value change and in case p1 gets assigned before p2, this could take unexpected path and if p2 value change is not explicitly also handled properly in this case, could lead to mismatched state.