Details
-
Suggestion
-
Resolution: Done
-
P3: Somewhat important
-
None
-
None
-
4.7 cloned from qt git repo
Description
Problem:
I have a following structure:
- a C++ class MyClass containing as a property "QDeclarativePropertyMap * extra_properties"
- the class has a public slot addExtraProperty(const QString &) which adds a property to extra_properties
- qml creates an instance of MyClass
What I want is to add a property "age" to myInstance.extra_properties and then bind myInstance.extra_properties.age to some properties of another object.
To add properties I have to call MyClass::addExtraProperty(), and the first place where I can do this from qml is Component.onCompleted. The problem is that the bindings are created before this happens...
So if I put this in test.qml:
MyClass { id: myInstance Component.onCompleted: { addExtraProperty("age"); } } Binding { target: myInstance.extra_properties property: "age" value: myOtherObject.some_value }
(together with parts defining myOtherObject etc.) then calling setSource("test.qml") for a QDeclarativeView segfaults (backtrace shows that this indeed happens during creation of bindings).
But if I postpone binding in any way (e.g. add "when" to above binding:
Binding { target: myInstance property: "age" value: myOtherObject.some_value when: myOtherObject.state != "intial_state" }
or get rid of this Binding and instead add
State {
name: "NOT_initial_state"
PropertyChanges { target: myInstance.extra_properties; age: myOtherObject.some_value }
}
) then this works perfectly: the property "age" is added and gets bound. Still, it is weird from clarity point of view (there is nothing special in being in not-initial state from myInstance point of view, it's just a workaround to do bindings in deferred way) and in extreme case it would require adding e.g. some useless initial state (just to be able to do some initialization when we leave this initial state...) or some other workaround.
================================
I understand (from e.g. description of QDeclarativeParserStatus) that creation of objects in qml happens in two stages:
- stage 1: C++ object is created: there are no bindings, initial values are not set yet
- then classBegin() is called
- stage 2: initial values of properties are set and properites get bound
- then componentComplete() is called which after a chain of calls ends up with emission of signal completed() [ "emit a->completed();" in qdeclarativecomponent.cpp?]
================================
Request:
I think what I described above (dynamic creation of properties which preferably would get immediately/unconditionally bound) is a rather rare case, but still it would be great if there was a new signal added (e.g. "halfready()" ) which would be emitted from classBegin(), i.e. between stage1 and stage2, that is at the moment when the object exists (thus new dynamic properties can be added) but no bindings are added yet.
Then my qml would look like this:
MyClass { id: myInstance // this is the line that is changed: Component.onHalfready: { addExtraProperty("age"); } } Binding { target: myInstance.extra_properties property: "age" value: myOtherObject.some_value }
and it would almost certainly simply work.