Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

How to bind TextInput.text to QString property in two ways?



  • Hello,
    I try to bind a QML TextInput to a QString-property of a C++-QObject. My expectation is that the text in the TextInput is updated whenever the NOTIFY-signal of that property is fired AND that the setter of that property is called whenever the text in the TextInput is changed by the user. However, I can only see the first behaviour. I created a small example that has a QLineEdit and a QDeclarativeView in a layout. The lineEdit is exposed to the QML-file using a context property. Now I bind to the property using this QML-file:

    @
    import Qt 4.7
    Rectangle {
    width: 240
    height: 320

    TextInput {
        text: lineEdit.text
        anchors.fill: parent
    }
    

    }@

    Whenever I change the text in the QLineEdit now, the TextInput within the declarative view is updated. However, when I change the test in the TextInput, nothing happens. I expected that the QLineEdit would be updated as well. Is this intended behavior? If yes, how to keep both in sync? Shouldn't a declarative binding work in two ways?



  • take a look at this example on forum nokia: "http://wiki.forum.nokia.com/index.php/CS001625_-Connecting_Qt_signal_to_QML_function":http://wiki.forum.nokia.com/index.php/CS001625-_Connecting_Qt_signal_to_QML_function



  • Thank you but this does not help because it is just an alternate way to do the part that already works. I want the C++ lineedit to be updated from the QML one. And I actually want to do it in a declarative way and not an imperative way.



  • Hi,

    QML currently only supports "one-way" bindings. You can use the "Binding":http://doc.qt.nokia.com/4.7/qml-binding.html element if you want to bind lineEdit.text to the text of the TextInput as well.

    @
    import Qt 4.7
    Rectangle {
    width: 240
    height: 320

    TextInput {
        id: input
        text: lineEdit.text
        anchors.fill: parent
    }
    Binding {
        target: lineEdit
        property: "text"
        value: input.text
    }
    

    }
    @

    Regards,
    Michael



  • Thank you. This is exactly the information I was looking for.



  • Hi,

    Doing this will generate a console warning:

    QML TextInput: Binding loop detected for property "text"

    It works nevertheless but I don't like warnings.

    Any ideas?

    Regards

    Nils



  • File a bugreport :-)



  • Well, it actually is a binding loop. However it does not do any harm as long as the setter on the C++ side is implemented correctly.



  • I meant it more as: file a bug report with a suggestion to make two way bindings possible :-)



  • [quote author="njeisecke" date="1305030760"]Hi,

    Doing this will generate a console warning:

    QML TextInput: Binding loop detected for property "text"

    It works nevertheless but I don't like warnings.

    Any ideas?
    [/quote]

    Hi Nils,

    Is it the exact snippet above (with a QLineEdit in C++) you are testing or something else?

    Typically this warning is avoided via the C++ implementation of the setter, e.g. setText() will be implemented to only emit the NOTIFY signal if the property actually changes. I thought in this case both TextInput and QLineEdit would have done this, though (so there might be something else at play here that I've missed).

    Regards,
    Michael



  • Are you suggesting that Qt Quick is at runtime able to analyze if the (C++) objects block emitting a changed signal if you set the same value on a property? And that they only should give the Binding Loop warning if they don't block the signal? That would be pretty cool! But I think that is unlikely. I think it is a warning because it can not be detected if the signal is emitted. If it could, it would (should) be an error instead.



  • Hi Michael,

    my setter was on the c++ side and indeed wrongly implemented (stupid me).

    With an implementation like this everything works as expected:

    @
    void MyObject::setValue(const QString &value)
    {
    // this avoids the (absolutely correct) warning
    if (m_value == value)
    return;

    m_value = value;
    emit valueChanged():
    }
    @

    So actually there seems to be some runtime analysis. Cool ;-)



  • Does implementing it like this fix the warning? That would be awesome!
    If so, then perhaps the warning should be an error instead?



  • Yes it does, I've just commented out the check and the warning appears.


Log in to reply