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 since parameters changed, parameters.name needs to be "re-binded" ?

    Thanks !


  • Moderators

    @ebatsin said in property binding on object chain:
    "nested" properties do not emit such a binding, you could try a Binding element

     Text {
            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 the value 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 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
            ....
        }
    }
    

    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 from null 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 :)


  • Moderators

    @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 ?


  • Moderators

    @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


  • Qt Champions 2018

    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.


 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.