Solved property binding on object chain
-
Hi!
I am trying to have a
Text
get the value of a property of a C++ object that can sometimes be null.I have 2 C++ objects:
Project:
class Project : public QObject { Q_OBJECT Q_PROPERTY(Parameters* parameters READ parameters NOTIFY parametersChanged) /* definintion of parameters getter/setter/signal. The setter emits the parametersChanged signal */ };
Parameters:
class Parameters: public QObject { Q_OBJECT Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) /* definintion of name getter/setter/signal. The setter emits the nameChanged signal */ };
Now, in my QML, I have:
Text { text: myProject.parameters.name }
But this does not work. The name is never filled because my project starts with its
parameters
property set to null. When the property is filled, QML registers it, but after that, if name changes, nothing is happening in QML.I tried:
Text { text: myProject.parameters ? myProject.parameters.name : '' Connections { target: myProject: onParametersChanged: { console.log('parameters changed') } // emitted and received } }
My question being: Is there a way to force the binding to be reprocessed entirely when
parameters
changes so that it will detect that sinceparameters
changed,parameters.name
needs to be "re-binded" ?Thanks !
-
@ebatsin said in property binding on object chain:
"nested" properties do not emit such a binding, you could try a Binding elementText { id: t Binding { when: myProject.parameters value: myProject.parameters.name target: t property: "text" } }
(untested)
-
@ebatsin said in property binding on object chain:
The name is never filled
Are you explicitly emitting the signals when you change the value in C++? Are you changed it in C++, QML, or both?
-
@raven-worx
Thanks, this works in the case I explained previously (depth 2 nesting) but I get an error at thevalue
line of the binding in QML (even though it works):
TypeError: Cannot read property 'name' of null
But is there a way that would be robust to something like that:
project.parameters.angles.roll
where bothparameters
andangles
could be null be null ?Since I can't do:
Text { id: t Binding { when: project.parameters.angles // do not work when parameters is null .... } }
This is more of a theorical question since I do not expect this problem to happen in my use case.
Also, is there somewhere documentation/blog post/article that explains why nested properties bindings are not re-evaluated if one part of the nested chains changes (ie:parameters
goes fromnull
to a valid pointer) ?@fcarney
The signals are explicitly emitted when the value is changed:void Project::setParameters(Parameters* parameters) { if(d->parameters != parameters) { d->parameters = parameters; emit parametersChanged(); } }
void Parameters::setName(QString const& name) { if(d->name != name) { d->name = name; emit nameChanged(); } }
The values are changed exclusively from C++ (controlled by a
QStateMachine
)Thanks for your help :)
-
@ebatsin said in property binding on object chain:
But is there a way that would be robust to something like that: project.parameters.angles.roll where both parameters and angles could be null be null ?
Since I can't do:
Text {
id: t
Binding {
when: project.parameters.angles // do not work when parameters is null
....
}
}Binding { when: project.parameters && project.parameters.angles }
-
@raven-worx Indeed. Should have found that one alone :/
I still get an error when the QML is parsed which is not really sexy in my application logs (but the binding works so I'll call it a win for now).
As I said before, is there somewhere that explains why nested bindings are not re-evaluated if a property in the middle of the chain changes ?
-
@ebatsin said in property binding on object chain:
As I said before, is there somewhere that explains why nested bindings are not re-evaluated if a property in the middle of the chain changes ?
i am not aware of an explaination of this behavior.
But i am thinking of the following:
A triggering of the the parent property might notify other bindings even if actually nothing has changed for that particular binding -
You could just do :
Text { text: myProject.parameters && myProject.parameters.name || "" }
Nested properties ARE re-evaluated if a property in the middle of the chain changes.
-
@GrecKo This won't work. Although changing
parameters
will make thetext
to be re-eavaluted, changing of the nested propertyname
won't trigger thetext
to be re-evaluated. It is because initially the expression bind to thename
property of the oldparameters
instance.