Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. Strange binding behavior when using binding on array's element

Strange binding behavior when using binding on array's element

Scheduled Pinned Locked Moved QML and Qt Quick
qmlarraybinding
11 Posts 3 Posters 5.4k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • G geniuss
    18 Jul 2015, 11:30

    I have an Item with a property. This property contains array of javascript objects. Each javascript object has properties.
    When I set binding for one of object's properties to some variable and its (variable) value changes triggering the binding then all properties in the array get reevaluated.

    Consider the following code:

    import QtQuick 2.4
    import QtQuick.Controls 1.3
    
    ApplicationWindow {
        id: container
    
        width: 640
        height: 480
    
        property int clicksCounter: 0
        property string name : "default name"
    
        Item {
            id: testObject
            property var myArray : [{
                name : container.name,
                boolFlag : false
            }]
        }
    
        Rectangle {
            x: 10
            y: 10
    
            width: 100
            height: 100
            color: "red"
    
            MouseArea {
                anchors.fill: parent
                onClicked: {
                    container.clicksCounter++
    
                    console.log("CLICK #" + container.clicksCounter + "[RED SQUARE] : Changing value for property container.name and setting true to 'boolFlag' property of first array's element\n")
                    var element = testObject.myArray[0]
    
                    console.log("CLICK #" + container.clicksCounter + "[RED SQUARE] : [BEFORE] testObject.myArray[0].name: " + element.name + ', testObject.myArray[0].boolFlag: ' + element.boolFlag)
                    container.name = "new name"
                    element.boolFlag = true
                    console.log("CLICK #" + container.clicksCounter + "[RED SQUARE] : [AFTER] testObject.myArray[0].name: " + element.name + ', testObject.myArray[0].boolFlag: ' + element.boolFlag + "\n")
                }
            }
        }
    
        Rectangle {
            x: 120
            y: 10
    
            width: 100
            height: 100
            color: "blue"
    
            MouseArea {
                anchors.fill: parent
                onClicked: {
                    container.clicksCounter++
    
                    var element = testObject.myArray[0]
                    console.log("CLICK #" + container.clicksCounter + "[BLUE SQUARE] : testObject.myArray[0].name: " + element.name + ', testObject.myArray[0].boolFlag: ' + element.boolFlag + "\n")
                }
            }
        }
    }
    

    Clicking red square changes the value of array, clicking blue square shows current boolean value of the flag.
    Here are the results of clicking the squares:

    (1)
    qml: CLICK #1[BLUE SQUARE] : testObject.myArray[0].name: default name, testObject.myArray[0].boolFlag: false

    (2)
    qml: CLICK #2[RED SQUARE] : Changing value for property container.name and setting true to 'boolFlag' property of first array's element

    qml: CLICK #2[RED SQUARE] : [BEFORE] testObject.myArray[0].name: default name, testObject.myArray[0].boolFlag: false
    qml: CLICK #2[RED SQUARE] : [AFTER] testObject.myArray[0].name: default name, testObject.myArray[0].boolFlag: true

    (3)
    qml: CLICK #3[BLUE SQUARE] : testObject.myArray[0].name: new name, testObject.myArray[0].boolFlag: false

    Why is testObject.myArray[0].boolFlag equals FALSE on click 3 if its value was set to TRUE on click 2?

    P Offline
    P Offline
    p3c0
    Moderators
    wrote on 18 Jul 2015, 12:17 last edited by p3c0
    #2

    Hi @geniuss

    var element = testObject.myArray[0]
    element.boolFlag = true
    

    Here you are updating the copy and not that object in array. Replace element with testObject.myArray[0] and you should notice the update.

    157

    1 Reply Last reply
    0
    • G Offline
      G Offline
      geniuss
      wrote on 18 Jul 2015, 12:46 last edited by
      #3

      Indeed, you're correct. This example was supposed to be a simulation of a problem from a real project which is too big to be posted in full here.
      But this example is wrong. I will make another example once I figure out how to reproduce the problem.

      1 Reply Last reply
      0
      • X Offline
        X Offline
        xargs1
        wrote on 18 Jul 2015, 20:43 last edited by
        #4

        Keep in mind that bindings to "var" properties may not work as expected since they don't emit "changed" signals when they're modified. You might need to manually call myArrayChanged() after modifying it for the binding to work as expected.

        1 Reply Last reply
        0
        • G Offline
          G Offline
          geniuss
          wrote on 20 Jul 2015, 12:26 last edited by geniuss
          #5

          Okay, I managed to reproduce it. But for this I had to add C++ part.

          C++ code is this:

          // main.cpp
          #include <QGuiApplication>
          #include <QQuickWindow>
          #include <QQmlApplicationEngine>
          #include <QQmlContext>
          
          class Test : public QObject
          {
          
              Q_OBJECT
                  Q_PROPERTY(QString emptyString READ getEmptyString NOTIFY valueChanged)
                  QString getEmptyString(){ return ""; }
          
          public:
              Test(QObject* parent = 0) : QObject(parent) {}
          
              Q_INVOKABLE void triggerNotify()
              {
                  valueChanged();
              }
          
          signals:
              void valueChanged();
          };
          
          int main(int argc, char *argv[])
          {
              QGuiApplication app(argc, argv);
              
              QQmlApplicationEngine engine;
              Test* test = new Test(&engine);
              engine.rootContext()->setContextProperty("__test__", (QObject*)test);
              QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, [](QObject* rootObject) {
                  QQuickWindow *appWindow = qobject_cast<QQuickWindow *>(rootObject);
                  appWindow->show();
              });
          
              engine.load(QUrl(QStringLiteral("qrc:/ui/main.qml")));
              return app.exec();
          }
          

          QML code is this:

          // main.qml
          import QtQuick 2.4
          import QtQuick.Controls 1.3
          
          ApplicationWindow {
              id: container
          
              width: 640
              height: 480
          
              property int clicksCounter: 0
          
              Item {
                  id: testObject
                  property var myArray : [{
                      name : "CustomName" + __test__.emptyString,
                      boolFlag : false
                  }]
              }
          
              Rectangle {
                  x: 10
                  y: 10
          
                  width: 100
                  height: 100
                  color: "red"
          
                  MouseArea {
                      anchors.fill: parent
                      onClicked: {
                          container.clicksCounter++
          
                          console.log("CLICK #" + container.clicksCounter + "[RED SQUARE] : Set testObject.myArray[0] to TRUE\n")
                          testObject.myArray[0].boolFlag = true
                          console.log("CLICK #" + container.clicksCounter + "[RED SQUARE] : DONE\n")
                      }
                  }
              }
          
              Rectangle {
                  x: 120
                  y: 10
          
                  width: 100
                  height: 100
                  color: "blue"
          
                  MouseArea {
                      anchors.fill: parent
                      onClicked: {
                          container.clicksCounter++
          
                          console.log("CLICK #" + container.clicksCounter + "[BLUE SQUARE] : Triggering notify by calling C++ <Test::triggerNotify> method \n")
                          console.log("CLICK #" + container.clicksCounter + "[BLUE SQUARE] : [BEFORE] testObject.myArray[0].name: " + testObject.myArray[0].name + ', testObject.myArray[0].boolFlag: ' + testObject.myArray[0].boolFlag)
                          __test__.triggerNotify()
                          console.log("CLICK #" + container.clicksCounter + "[BLUE SQUARE] : [AFTER] testObject.myArray[0].name: " + testObject.myArray[0].name + ', testObject.myArray[0].boolFlag: ' + testObject.myArray[0].boolFlag)
                      }
                  }
              }
          }
          

          Here is what I get:

          qml: CLICK #1[RED SQUARE] : Set testObject.myArray[0] to TRUE
          qml: CLICK #1[RED SQUARE] : DONE

          qml: CLICK #2[BLUE SQUARE] : Triggering notify by calling C++ Test::triggerNotify method

          qml: CLICK #2[BLUE SQUARE] : [BEFORE] testObject.myArray[0].name: CustomName, testObject.myArray[0].boolFlag: true
          qml: CLICK #2[BLUE SQUARE] : [AFTER] testObject.myArray[0].name: CustomName, testObject.myArray[0].boolFlag: false

          So what happens here is that after I set testObject.myArray[0].boolFlag from FALSE to TRUE and call test.triggerNotify() method my flag automatically resets to its initial value. Same goes if any other type used - int, string, etc. Why does this happen?

          [UPDATE] QT 5.5 is used, Visual Studio 2013 Update 4 x32.

          P 1 Reply Last reply 21 Jul 2015, 06:48
          0
          • G geniuss
            20 Jul 2015, 12:26

            Okay, I managed to reproduce it. But for this I had to add C++ part.

            C++ code is this:

            // main.cpp
            #include <QGuiApplication>
            #include <QQuickWindow>
            #include <QQmlApplicationEngine>
            #include <QQmlContext>
            
            class Test : public QObject
            {
            
                Q_OBJECT
                    Q_PROPERTY(QString emptyString READ getEmptyString NOTIFY valueChanged)
                    QString getEmptyString(){ return ""; }
            
            public:
                Test(QObject* parent = 0) : QObject(parent) {}
            
                Q_INVOKABLE void triggerNotify()
                {
                    valueChanged();
                }
            
            signals:
                void valueChanged();
            };
            
            int main(int argc, char *argv[])
            {
                QGuiApplication app(argc, argv);
                
                QQmlApplicationEngine engine;
                Test* test = new Test(&engine);
                engine.rootContext()->setContextProperty("__test__", (QObject*)test);
                QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, [](QObject* rootObject) {
                    QQuickWindow *appWindow = qobject_cast<QQuickWindow *>(rootObject);
                    appWindow->show();
                });
            
                engine.load(QUrl(QStringLiteral("qrc:/ui/main.qml")));
                return app.exec();
            }
            

            QML code is this:

            // main.qml
            import QtQuick 2.4
            import QtQuick.Controls 1.3
            
            ApplicationWindow {
                id: container
            
                width: 640
                height: 480
            
                property int clicksCounter: 0
            
                Item {
                    id: testObject
                    property var myArray : [{
                        name : "CustomName" + __test__.emptyString,
                        boolFlag : false
                    }]
                }
            
                Rectangle {
                    x: 10
                    y: 10
            
                    width: 100
                    height: 100
                    color: "red"
            
                    MouseArea {
                        anchors.fill: parent
                        onClicked: {
                            container.clicksCounter++
            
                            console.log("CLICK #" + container.clicksCounter + "[RED SQUARE] : Set testObject.myArray[0] to TRUE\n")
                            testObject.myArray[0].boolFlag = true
                            console.log("CLICK #" + container.clicksCounter + "[RED SQUARE] : DONE\n")
                        }
                    }
                }
            
                Rectangle {
                    x: 120
                    y: 10
            
                    width: 100
                    height: 100
                    color: "blue"
            
                    MouseArea {
                        anchors.fill: parent
                        onClicked: {
                            container.clicksCounter++
            
                            console.log("CLICK #" + container.clicksCounter + "[BLUE SQUARE] : Triggering notify by calling C++ <Test::triggerNotify> method \n")
                            console.log("CLICK #" + container.clicksCounter + "[BLUE SQUARE] : [BEFORE] testObject.myArray[0].name: " + testObject.myArray[0].name + ', testObject.myArray[0].boolFlag: ' + testObject.myArray[0].boolFlag)
                            __test__.triggerNotify()
                            console.log("CLICK #" + container.clicksCounter + "[BLUE SQUARE] : [AFTER] testObject.myArray[0].name: " + testObject.myArray[0].name + ', testObject.myArray[0].boolFlag: ' + testObject.myArray[0].boolFlag)
                        }
                    }
                }
            }
            

            Here is what I get:

            qml: CLICK #1[RED SQUARE] : Set testObject.myArray[0] to TRUE
            qml: CLICK #1[RED SQUARE] : DONE

            qml: CLICK #2[BLUE SQUARE] : Triggering notify by calling C++ Test::triggerNotify method

            qml: CLICK #2[BLUE SQUARE] : [BEFORE] testObject.myArray[0].name: CustomName, testObject.myArray[0].boolFlag: true
            qml: CLICK #2[BLUE SQUARE] : [AFTER] testObject.myArray[0].name: CustomName, testObject.myArray[0].boolFlag: false

            So what happens here is that after I set testObject.myArray[0].boolFlag from FALSE to TRUE and call test.triggerNotify() method my flag automatically resets to its initial value. Same goes if any other type used - int, string, etc. Why does this happen?

            [UPDATE] QT 5.5 is used, Visual Studio 2013 Update 4 x32.

            P Offline
            P Offline
            p3c0
            Moderators
            wrote on 21 Jul 2015, 06:48 last edited by p3c0
            #6

            @geniuss Here is you answer:
            http://doc.qt.io/qt-5/qml-var.html#change-notification-semantics
            Edit: But that doesn't justify why it becomes false O_o

            157

            1 Reply Last reply
            0
            • G Offline
              G Offline
              geniuss
              wrote on 21 Jul 2015, 10:13 last edited by
              #7

              Exactly, there is no connection between "change notification semantics" for "var" and my problem.

              P 1 Reply Last reply 21 Jul 2015, 11:01
              0
              • G geniuss
                21 Jul 2015, 10:13

                Exactly, there is no connection between "change notification semantics" for "var" and my problem.

                P Offline
                P Offline
                p3c0
                Moderators
                wrote on 21 Jul 2015, 11:01 last edited by
                #8

                @geniuss I think that is the way how it works. A change of that string will trigger reevaluation of the property myArray and thus causing the boolFlag to get its original value i.e false.

                157

                1 Reply Last reply
                0
                • G Offline
                  G Offline
                  geniuss
                  wrote on 21 Jul 2015, 13:54 last edited by
                  #9

                  This is madness then :) It should not work that way normally in my understanding.
                  Perhaps I'll post this as a bug if no one gives me a suitable answer.

                  P 1 Reply Last reply 21 Jul 2015, 16:15
                  0
                  • G geniuss
                    21 Jul 2015, 13:54

                    This is madness then :) It should not work that way normally in my understanding.
                    Perhaps I'll post this as a bug if no one gives me a suitable answer.

                    P Offline
                    P Offline
                    p3c0
                    Moderators
                    wrote on 21 Jul 2015, 16:15 last edited by
                    #10

                    @geniuss I would suggest you to ask at Qt Interest Mailing List. You can get an answer directly from Qt Engineers regarding these internals.

                    157

                    1 Reply Last reply
                    0
                    • G Offline
                      G Offline
                      geniuss
                      wrote on 23 Jul 2015, 14:48 last edited by
                      #11

                      @p3c0 I tried but that didn't work. Folks on Stack Overflow don't know either. I got no other choice :
                      https://bugreports.qt.io/browse/QTBUG-47407

                      1 Reply Last reply
                      0

                      11/11

                      23 Jul 2015, 14:48

                      • Login

                      • Login or register to search.
                      11 out of 11
                      • First post
                        11/11
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt Extensions
                      • Unsolved