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. Javascript assignment destroys property binding
Forum Updated to NodeBB v4.3 + New Features

Javascript assignment destroys property binding

Scheduled Pinned Locked Moved QML and Qt Quick
11 Posts 3 Posters 3.5k Views 1 Watching
  • 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.
  • F Offline
    F Offline
    flobe
    wrote on last edited by
    #1

    Lets have following QML code snippet:

    @
    import QtQuick 2.0

    Column {
    width: 200
    height: 200

    Rectangle {
        id: redRect
    
        color: "red"
        width: 100; height: 100
    
        NumberAnimation on width {
            duration: 1000
            loops: Animation.Infinite
            from: 100; to: 200
        }
    }
    
    Rectangle {
        color: "green"
        width: redRect.width; height: 100
    
        MouseArea {
            anchors.fill: parent
            onClicked: parent.width = 100
        }
    }
    

    }
    @

    The widths of the red and green rectangles are bound to each other by property binding. As soon as the Javascript assignment in MouseArea.onClicked is executed, the mentioned property binding is destroyed silently.

    I understand that an assignment to a property that is target of a property binding could be considerd bad code but is it intentional that this goes silently without any error or warning?

    P.S.: Sorry if this is a duplicate. I didn't find a similar thread.

    1 Reply Last reply
    0
    • F Offline
      F Offline
      flobe
      wrote on last edited by
      #2

      I can ask my question slighty differently: Is there any way in QML to do something like this:

      @
      // ToggleButton.qml
      import QtQuick 2.0

      Rectangle {
      property bool status: false

      width: childrenRect.width
      height: childrenRect.height
      
      Text {
          text: parent.status ? "On" : "Off"
      }
      
      MouseArea {
          anchors.fill: parent
          onClicked: parent.status = !parent.status
      }
      

      }
      @

      @
      // main.qml
      import QtQuick 2.0

      Column {
      width: 200
      height: 200
      spacing: 10

      ToggleButton {
          id: btn1
      
          status: btn2.status
      }
      
      ToggleButton {
          id: btn2
      
          status: btn1.status
      }
      

      }
      @

      As long is I only press one button everything works fine. But as soon as I press the second button one of the bindings get destroyed.

      Is there any way in QML to implement that behavior without the binding getting destroyed while having ToggleButton as a reusable QML component?

      Of course I can use onStatusChanged signals instead of property bindings on the status properties directly. But then I need to inform the component's user to not use property bindings on that property which is not very user-friendly and error-prone.

      1 Reply Last reply
      0
      • C Offline
        C Offline
        chrisadams
        wrote on last edited by
        #3

        You can use the States and Animations framework to do this, as the State change will cause the appropriate binding to be set.
        Alternatively, you can assign the result of Qt.binding() to assign a binding imperatively.

        1 Reply Last reply
        0
        • JKSHJ Offline
          JKSHJ Offline
          JKSH
          Moderators
          wrote on last edited by
          #4

          Hi, your situation and Chris' solution are both described in detail in this document: "Creating Property Bindings in JavaScript":http://qt-project.org/doc/qt-5/qtqml-syntax-propertybinding.html#creating-property-bindings-from-javascript

          Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

          1 Reply Last reply
          0
          • F Offline
            F Offline
            flobe
            wrote on last edited by
            #5

            Hm, I don't quite understand your solution. The reference document doesn't help so much as it only describes the fact that the binding disappears on a Javascript assignment. Setting the binding imperatively in ToggleButton.qml is not possible because it is not known at that place.

            How can I create a reusable component that has properties that can be bound to from the outside while also being set inside by a Javascript expression?

            1 Reply Last reply
            0
            • JKSHJ Offline
              JKSHJ Offline
              JKSH
              Moderators
              wrote on last edited by
              #6

              Ah sorry, I misunderstood your original posts.
              [quote author="flobe" date="1404393682"]
              @
              ToggleButton {
              id: btn1

                  status: btn2.status
              }
              
              ToggleButton {
                  id: btn2
              
                  status: btn1.status
              }
              

              @
              [/quote]First, you need to understand that your above code has a binding loop, which is illegal. You can't have btn1.status and btn2.status depend on each other; one of them needs to be independent. I'm surprised that your bindings actually worked in the beginning, as the QML engine should complain about binding loops.

              Here's another example of a binding loop:
              @
              Rectangle {
              // What values should width and height be?
              width: height
              height: width
              }
              @

              [quote author="flobe" date="1405086712"]How can I create a reusable component that has properties that can be bound to from the outside while also being set inside by a Javascript expression?[/quote]Hmm... I'm unsure how you want your component to behave.

              When you use property bindings, you make one property dependent on another.

              Consider this example:

              @
              property bool externalFlag: false

              ToggleButton {
              id: myButton
              status: parent.externalFlag
              }
              @

              The above snippet says: myButton.status should always copy the value of externalFlag. In other words, whenever externalFlag changes, myButton.status will change too to stay synchronized.

              So at startup, myButton.status copies the value of externalFlag. But, what should happen when you click myButton? There are 3 possibilities:

              myButton.status should toggle, becoming the opposite of externalFlag

              myButton.status should remain the same as externalFlag (in other words, the click should be ignored).

              myButton.status and externalFlag should both toggle

              Which do you want? (If you want #3, then your binding is the wrong way round -- externalFlag should depend on myButton.status instead)

              Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

              1 Reply Last reply
              0
              • F Offline
                F Offline
                flobe
                wrote on last edited by
                #7

                Well, I'm looking for a reusable toggle button component which state (on or off) can be controlled by a mouse click (which results in - as far as I see - a Javascript assignment) as well as from a state property of another QML item.

                Currently I use the onStatusChanged signals to assign the new state to the toggle button and vice versa:

                @
                onStatusChanged: btn2.status = status
                @

                I consider this solution as not very maintainable because the user of the toggle button component must know about implementation details in order to use the onStatusChanged signal instead of a property binding.

                I have just checked the CheckBox implementation of QtQuick.Controls which show the same problem. It is not possible to keep two CheckBox items in sync by using property bindings. But using the onCheckedChanged signals it works.

                From my point of view the former approach should at least lead to a runtime warning when destroying the property binding in order for the component's user to detect such a subtle error.

                1 Reply Last reply
                0
                • JKSHJ Offline
                  JKSHJ Offline
                  JKSH
                  Moderators
                  wrote on last edited by
                  #8

                  Refer to my previous post again: Which behaviour are you expecting when you click the button? #1, #2 or #3?

                  Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

                  1 Reply Last reply
                  0
                  • F Offline
                    F Offline
                    flobe
                    wrote on last edited by
                    #9

                    Behavior #3.

                    1 Reply Last reply
                    0
                    • JKSHJ Offline
                      JKSHJ Offline
                      JKSH
                      Moderators
                      wrote on last edited by
                      #10

                      [quote author="flobe" date="1405166984"]Behavior #3.[/quote]Then your property binding needs to be the other way round.

                      @
                      // Error: Dependency is the wrong way round
                      property bool externalFlag

                      ToggleButton {
                      id: myButton
                      status: parent.externalFlag
                      }
                      @

                      @
                      // Ok: externalFlag toggles when myButton is toggled
                      property bool externalFlag: myButton.status

                      ToggleButton {
                      id: myButton
                      }
                      @

                      @
                      // Error: Binding loop, also known as "circular dependency"
                      property bool externalFlag: myButton.status

                      ToggleButton {
                      id: myButton
                      status: parent.externalFlag
                      }
                      @

                      Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

                      1 Reply Last reply
                      0
                      • JKSHJ Offline
                        JKSHJ Offline
                        JKSH
                        Moderators
                        wrote on last edited by
                        #11

                        [quote author="flobe" date="1405152382"]Well, I'm looking for a reusable toggle button component which state (on or off) can be controlled by a mouse click (which results in - as far as I see - a Javascript assignment) as well as from a state property of another QML item.

                        ...

                        I have just checked the CheckBox implementation of QtQuick.Controls which show the same problem. It is not possible to keep two CheckBox items in sync by using property bindings.[/quote]I think that makes sense.

                        A CheckBox and ToggleButton have a boolean property. Usually, the mouse controls that property.

                        If you bind that property to an external boolean variable, then the external variable will also try to control that property. You now have two different and unsynchronized things trying to write to that property -- this can create conflicts, as you've discovered.

                        I think your onStatusChanged solution is the only way to achieve what you want.

                        Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

                        1 Reply Last reply
                        0

                        • Login

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