Home > Blockchain >  Order of QML property's dependency evaluation
Order of QML property's dependency evaluation

Time:12-21

I have a CustomQMLComponent. It has 3 properties. p3 is dependent on p1 & p2. p1 & p2 are set when an instance of CustomQMLComponent is created.

Questions:

  1. By the time p3 is evaluated, will p1 & p2 always have the values set by the caller.
  2. What is the recommended way to set p3, as shown below or as in the commented statement?

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
}

UPDATE:

p1 and p2 have static value assignments, whereas p3 has a binding value assignment.
As per this old article: https://www.kdab.com/qml-engine-internals-part-2-bindings/, static value assignments happen during creation phase and binding value assignments happen at the end of creation phase.

Case 1:

CustomQMLComponent{}

In this case, based on the above article, p1 & p2 values are set by the time p3 value is set.

Case 2:

CustomQMLComponent{
    p1: "my_string"
    p2: true
}

What happens in this case?

In a more general sense, what happens when properties of a component are set when creating an instance of the component? Are the properties initialized with default values and then overridden by the new instance's values? Or, the properties are initialized just once with the default/new values.

CodePudding user response:

This line is not just an assignment, it is also a binding:

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

What that means is that it will be reevaluated every time a property referred to in it (in this case p1 and p2) changes - i.e. their *Changed event is emitted.

So, it doesn't really matter as long as anything dependent on p3 can handle p3 changing value multiple times and the slot method can handle the various values for p1 and p2 as they settle.

To see the exact sequence of what will happen in this particular case, add onP1Changed, onP2Changed and onP3Changed event handlers and log their values to the console.

CodePudding user response:

Response from Qt Support:

As per this old article: https://www.kdab.com/qml-engine-internals-part-2-bindings/, static value assignments happen during creation phase and binding value assignments happen at the end of creation phase.

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}

Case 1:

CustomQMLComponent{}

In this case, based on the above article, p1 & p2 values are set by the time p3 value is set.

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.

Case 2:

CustomQMLComponent{
    p1: "my_string"
    p2: true
}

What happens in this case?

In a more general sense, what happens when properties of a component are set when creating an instance of the component? Are the properties initialized with default values and then overridden by the new instance's values? Or, the properties are initialized just once with the default/new values.

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.

  • Related