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. C++ QProperty binding Question

C++ QProperty binding Question

Scheduled Pinned Locked Moved Solved QML and Qt Quick
14 Posts 5 Posters 1.3k 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.
  • dheerendraD Offline
    dheerendraD Offline
    dheerendra
    Qt Champions 2022
    wrote on last edited by dheerendra
    #1

    Following is the code snippet. Code is working properly. No issue with code. I have understanding issue. How this internally works.

    QProperty<int> height { 50};
     QProperty<int> width { 100};
    
     QProperty<int> area;
     area.setBinding([&](){
         qDebug() << " This is called one more time" << Qt::endl;
         return width * height;
     });
    
     width = 4;
     height = 40;
     width = 10;
    

    How the change in width or height triggers the re-evaluate of area ?
    Area is binded to lambda expression. Inside the lambda we have reference to width & height. How the notify(change) signal of width or height is bound to area ? Is there any parsing happens for lambda expression, finds the width or height & then it does the some thing ?
    Looking for an answer on binding is built internally.

    Dheerendra
    @Community Service
    Certified Qt Specialist
    http://www.pthinks.com

    JonBJ 2 Replies Last reply
    1
    • J.HilkJ J.Hilk

      @dheerendra

      cough cough My voice is not my own:

      The setBinding function itself doesn't directly analyze the lambda body or "know" about the variables width and height. Instead, the QProperty class provides a mechanism for registering dependencies between properties.

      When you call setBinding, you're essentially telling the QProperty object that the value of this property (area in your case) depends on the values of other properties, namely width and height.

      The lambda expression you provide is a function that calculates the value of the area property based on the values of width and height. However, it's not the lambda expression itself that the QProperty object "understands" or keeps track of; it's the fact that you've registered a dependency on width and height.

      Internally, when you call setBinding, the QProperty object can inspect the lambda expression and identify any external variables that are captured by reference. In your lambda & { return width * height; }, width and height are captured by reference (&), indicating that they are external variables used inside the lambda body.

      Once the QProperty object identifies these external variables, it stores them as dependencies for the property. So, whenever the values of these dependencies change (i.e., when width or height changes), the QProperty object knows that it needs to re-evaluate the binding function associated with the property.

      In essence, the QProperty class provides a mechanism for tracking dependencies between properties based on the information you provide when you set up bindings. It doesn't directly analyze the lambda body or "understand" the variables used inside it; it simply keeps track of the dependencies you specify.

      GrecKoG Offline
      GrecKoG Offline
      GrecKo
      Qt Champions 2018
      wrote on last edited by GrecKo
      #12

      @J-Hilk said in C++ QProperty binding Question:

      Internally, when you call setBinding, the QProperty object can inspect the lambda expression and identify any external variables that are captured by reference. In your lambda & { return width * height; }, width and height are captured by reference (&), indicating that they are external variables used inside the lambda body.

      No.

      The QProperty knows its dependency because when you call setBinding with a lambda, the lambda is executed and it tracks the other properties that are being evaluated in it.

      If both width and height are QProperty<int>.
      width * height is first calling the implicit QProperty<int>::operator int() for both, converting them to int so it can call the arithmetic operator * on their values. This operator int() is what is registering the dependency.

      To put it otherwise, when calling area.setBinding([&](){ return width * height; }); here is what happens:

      • the lambda is stored in the area QProperty to be called later.
      • area is marked as the current property being evaluated.
      • the lambda is then executed.
        • width is being accessed through its conversion operator, it is thus being registered as a dependency of the currently evaluated property (area here)
        • the same happens for height
      • the return value of the lambda is assigned to area
      • area is no longer marked as the currently evaluated property.

      After that, every time that width and height are changed, the lambda is being reevaluated and the above process redone.

      JonBJ dheerendraD 2 Replies Last reply
      3
      • dheerendraD dheerendra

        Following is the code snippet. Code is working properly. No issue with code. I have understanding issue. How this internally works.

        QProperty<int> height { 50};
         QProperty<int> width { 100};
        
         QProperty<int> area;
         area.setBinding([&](){
             qDebug() << " This is called one more time" << Qt::endl;
             return width * height;
         });
        
         width = 4;
         height = 40;
         width = 10;
        

        How the change in width or height triggers the re-evaluate of area ?
        Area is binded to lambda expression. Inside the lambda we have reference to width & height. How the notify(change) signal of width or height is bound to area ? Is there any parsing happens for lambda expression, finds the width or height & then it does the some thing ?
        Looking for an answer on binding is built internally.

        JonBJ Offline
        JonBJ Offline
        JonB
        wrote on last edited by
        #2

        @dheerendra
        Just a quick answer from me, I don't use QML so you may get a better answer from someone who does, I don't want to take up too much space.

        https://doc.qt.io/qt-6/qtqml-syntax-propertybinding.html does say:

        When a property's dependencies change in value, the property is automatically updated according to the specified relationship.

        Behind the scenes, the QML engine monitors the property's dependencies (that is, the variables in the binding expression). When a change is detected, the QML engine re-evaluates the binding expression and applies the new result to the property.

        And the example in https://doc.qt.io/qt-6/qtqml-syntax-propertybinding.html#using-keyword-this-keyword-with-property-binding does say

        To bind the Rectangle's height to its own width, the binding expression must explicitly refer to this.width (or alternatively, rect.width):

        This does imply to me that QML builds a "graph" for a binding which specifies each base property it references so it knows when to recalculate.

        J.HilkJ dheerendraD 2 Replies Last reply
        1
        • JonBJ JonB

          @dheerendra
          Just a quick answer from me, I don't use QML so you may get a better answer from someone who does, I don't want to take up too much space.

          https://doc.qt.io/qt-6/qtqml-syntax-propertybinding.html does say:

          When a property's dependencies change in value, the property is automatically updated according to the specified relationship.

          Behind the scenes, the QML engine monitors the property's dependencies (that is, the variables in the binding expression). When a change is detected, the QML engine re-evaluates the binding expression and applies the new result to the property.

          And the example in https://doc.qt.io/qt-6/qtqml-syntax-propertybinding.html#using-keyword-this-keyword-with-property-binding does say

          To bind the Rectangle's height to its own width, the binding expression must explicitly refer to this.width (or alternatively, rect.width):

          This does imply to me that QML builds a "graph" for a binding which specifies each base property it references so it knows when to recalculate.

          J.HilkJ Offline
          J.HilkJ Offline
          J.Hilk
          Moderators
          wrote on last edited by
          #3

          @JonB

          alt text

          this is c++ propertybindings, nothing QML related here

          the "new" kid on the block


          Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


          Q: What's that?
          A: It's blue light.
          Q: What does it do?
          A: It turns blue.

          JonBJ 1 Reply Last reply
          0
          • J.HilkJ J.Hilk

            @JonB

            alt text

            this is c++ propertybindings, nothing QML related here

            the "new" kid on the block

            JonBJ Offline
            JonBJ Offline
            JonB
            wrote on last edited by
            #4

            @J-Hilk said in C++ QProperty binding Question:

            this is c++ propertybindings, nothing QML related here

            Oh, damn, I should not have jumped in then, sorry! I assumed coz it was in QML and Qt Quick....

            1 Reply Last reply
            0
            • JonBJ JonB

              @dheerendra
              Just a quick answer from me, I don't use QML so you may get a better answer from someone who does, I don't want to take up too much space.

              https://doc.qt.io/qt-6/qtqml-syntax-propertybinding.html does say:

              When a property's dependencies change in value, the property is automatically updated according to the specified relationship.

              Behind the scenes, the QML engine monitors the property's dependencies (that is, the variables in the binding expression). When a change is detected, the QML engine re-evaluates the binding expression and applies the new result to the property.

              And the example in https://doc.qt.io/qt-6/qtqml-syntax-propertybinding.html#using-keyword-this-keyword-with-property-binding does say

              To bind the Rectangle's height to its own width, the binding expression must explicitly refer to this.width (or alternatively, rect.width):

              This does imply to me that QML builds a "graph" for a binding which specifies each base property it references so it knows when to recalculate.

              dheerendraD Offline
              dheerendraD Offline
              dheerendra
              Qt Champions 2022
              wrote on last edited by
              #5

              @JonB
              Thanks Jon. QML I have clarity.

              This is C++ code binding introduced in Qt 6+. Property binding in C++. This lamda expression confused me. I can write any code inside the lambda. I can refer the variables in side. Do something else etc. So how binding is built with variable which are referred in side the lambda.

              Dheerendra
              @Community Service
              Certified Qt Specialist
              http://www.pthinks.com

              JonBJ J.HilkJ 2 Replies Last reply
              0
              • dheerendraD dheerendra

                @JonB
                Thanks Jon. QML I have clarity.

                This is C++ code binding introduced in Qt 6+. Property binding in C++. This lamda expression confused me. I can write any code inside the lambda. I can refer the variables in side. Do something else etc. So how binding is built with variable which are referred in side the lambda.

                JonBJ Offline
                JonBJ Offline
                JonB
                wrote on last edited by JonB
                #6

                @dheerendra
                Well, I've jumped in here erroneously already so why not stick my head out further?

                Formulating a Property Binding still talks about

                Any C++ expression evaluating to the correct type can be used as a binding expression and be given to the setBinding() method. However, to formulate a correct binding, some rules must be followed.

                Dependency tracking only works on bindable properties. It's the developer's responsibility to ensure that all properties used in the binding expression are bindable properties. When non-bindable properties are used in a binding expression, changes to those properties do not trigger updates to the bound property. No warning or error is generated either at compile-time or at run-time. The bound property will be updated only when bindable properties used in the binding expression are changed

                So we are still talking about "tracking bindable properties in an expression" to decide whether the expression's value has changed. Per your template <typename Functor> QPropertyBinding<T> QProperty::setBinding(Functor f)

                The property's value is set to the result of evaluating the new binding. Whenever a dependency of the binding changes, the binding will be re-evaluated, and the property's value gets updated accordingly.

                I think the code really does see that you are accessing other properties and so update. But i really will shut up now, as you probably guessed this too!

                OK, finally I think this really does say it: under Qt Bindable Properties

                Qt provides bindable properties. Bindable properties are properties which either have a value or are specified using any C++ function, typically a C++ lambda expression. In case they are specified using a C++ function, they are updated automatically whenever their dependencies change.

                1 Reply Last reply
                1
                • dheerendraD dheerendra

                  @JonB
                  Thanks Jon. QML I have clarity.

                  This is C++ code binding introduced in Qt 6+. Property binding in C++. This lamda expression confused me. I can write any code inside the lambda. I can refer the variables in side. Do something else etc. So how binding is built with variable which are referred in side the lambda.

                  J.HilkJ Offline
                  J.HilkJ Offline
                  J.Hilk
                  Moderators
                  wrote on last edited by
                  #7

                  @dheerendra

                  cough cough My voice is not my own:

                  The setBinding function itself doesn't directly analyze the lambda body or "know" about the variables width and height. Instead, the QProperty class provides a mechanism for registering dependencies between properties.

                  When you call setBinding, you're essentially telling the QProperty object that the value of this property (area in your case) depends on the values of other properties, namely width and height.

                  The lambda expression you provide is a function that calculates the value of the area property based on the values of width and height. However, it's not the lambda expression itself that the QProperty object "understands" or keeps track of; it's the fact that you've registered a dependency on width and height.

                  Internally, when you call setBinding, the QProperty object can inspect the lambda expression and identify any external variables that are captured by reference. In your lambda & { return width * height; }, width and height are captured by reference (&), indicating that they are external variables used inside the lambda body.

                  Once the QProperty object identifies these external variables, it stores them as dependencies for the property. So, whenever the values of these dependencies change (i.e., when width or height changes), the QProperty object knows that it needs to re-evaluate the binding function associated with the property.

                  In essence, the QProperty class provides a mechanism for tracking dependencies between properties based on the information you provide when you set up bindings. It doesn't directly analyze the lambda body or "understand" the variables used inside it; it simply keeps track of the dependencies you specify.


                  Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


                  Q: What's that?
                  A: It's blue light.
                  Q: What does it do?
                  A: It turns blue.

                  JonBJ GrecKoG 2 Replies Last reply
                  2
                  • J.HilkJ J.Hilk

                    @dheerendra

                    cough cough My voice is not my own:

                    The setBinding function itself doesn't directly analyze the lambda body or "know" about the variables width and height. Instead, the QProperty class provides a mechanism for registering dependencies between properties.

                    When you call setBinding, you're essentially telling the QProperty object that the value of this property (area in your case) depends on the values of other properties, namely width and height.

                    The lambda expression you provide is a function that calculates the value of the area property based on the values of width and height. However, it's not the lambda expression itself that the QProperty object "understands" or keeps track of; it's the fact that you've registered a dependency on width and height.

                    Internally, when you call setBinding, the QProperty object can inspect the lambda expression and identify any external variables that are captured by reference. In your lambda & { return width * height; }, width and height are captured by reference (&), indicating that they are external variables used inside the lambda body.

                    Once the QProperty object identifies these external variables, it stores them as dependencies for the property. So, whenever the values of these dependencies change (i.e., when width or height changes), the QProperty object knows that it needs to re-evaluate the binding function associated with the property.

                    In essence, the QProperty class provides a mechanism for tracking dependencies between properties based on the information you provide when you set up bindings. It doesn't directly analyze the lambda body or "understand" the variables used inside it; it simply keeps track of the dependencies you specify.

                    JonBJ Offline
                    JonBJ Offline
                    JonB
                    wrote on last edited by JonB
                    #8

                    @J-Hilk said in C++ QProperty binding Question:

                    Internally, when you call setBinding, the QProperty object can inspect the lambda expression and identify any external variables that are captured by reference.

                    Once the QProperty object identifies these external variables, it stores them as dependencies for the property.

                    Exactly! But how does it have access to do that? The C++ lambda is compiled into code by the time it gets passed to setBinding(), is it not, so what calls are available to say "what variables/properties are referenced in this compiled C++ expression/functor"? I guess "reflection" somehow, but how does it even see that width or height are in the expression once it's compiled?

                    P.S.
                    Are these "Qt Bindable Properties" new at Qt6, so I (Qt5) cannot even play with them?

                    dheerendraD 1 Reply Last reply
                    0
                    • JonBJ JonB

                      @J-Hilk said in C++ QProperty binding Question:

                      Internally, when you call setBinding, the QProperty object can inspect the lambda expression and identify any external variables that are captured by reference.

                      Once the QProperty object identifies these external variables, it stores them as dependencies for the property.

                      Exactly! But how does it have access to do that? The C++ lambda is compiled into code by the time it gets passed to setBinding(), is it not, so what calls are available to say "what variables/properties are referenced in this compiled C++ expression/functor"? I guess "reflection" somehow, but how does it even see that width or height are in the expression once it's compiled?

                      P.S.
                      Are these "Qt Bindable Properties" new at Qt6, so I (Qt5) cannot even play with them?

                      dheerendraD Offline
                      dheerendraD Offline
                      dheerendra
                      Qt Champions 2022
                      wrote on last edited by
                      #9

                      @JonB @J-Hilk

                      Thank you. Yes QProperty is doing this. Unless some scanning of lambda happens it cannot achieve this. When does this happen ? How does it happen ? Some code scanning must happen. Is there some preprocessing like Moc. I know moc is not doing.

                      Any way code works. I have imagined like oh something happens like this. However when what how etc were not clear.

                      Dheerendra
                      @Community Service
                      Certified Qt Specialist
                      http://www.pthinks.com

                      jsulmJ 1 Reply Last reply
                      0
                      • dheerendraD dheerendra

                        @JonB @J-Hilk

                        Thank you. Yes QProperty is doing this. Unless some scanning of lambda happens it cannot achieve this. When does this happen ? How does it happen ? Some code scanning must happen. Is there some preprocessing like Moc. I know moc is not doing.

                        Any way code works. I have imagined like oh something happens like this. However when what how etc were not clear.

                        jsulmJ Offline
                        jsulmJ Offline
                        jsulm
                        Lifetime Qt Champion
                        wrote on last edited by
                        #10

                        @dheerendra Qt is open source you can look in the code to see how this overload of setBinding works

                        https://forum.qt.io/topic/113070/qt-code-of-conduct

                        1 Reply Last reply
                        0
                        • dheerendraD dheerendra

                          Following is the code snippet. Code is working properly. No issue with code. I have understanding issue. How this internally works.

                          QProperty<int> height { 50};
                           QProperty<int> width { 100};
                          
                           QProperty<int> area;
                           area.setBinding([&](){
                               qDebug() << " This is called one more time" << Qt::endl;
                               return width * height;
                           });
                          
                           width = 4;
                           height = 40;
                           width = 10;
                          

                          How the change in width or height triggers the re-evaluate of area ?
                          Area is binded to lambda expression. Inside the lambda we have reference to width & height. How the notify(change) signal of width or height is bound to area ? Is there any parsing happens for lambda expression, finds the width or height & then it does the some thing ?
                          Looking for an answer on binding is built internally.

                          JonBJ Offline
                          JonBJ Offline
                          JonB
                          wrote on last edited by
                          #11

                          @dheerendra
                          May I suggest you try this.

                          • To your properties add QProperty<int> dummy { 42 };
                          • To your lambda add qDebug() << "area being recalculated";.

                          Now try altering the value of dummy, only. Does the qDebug() get called?

                          • If it does then re-evaluation is not tied to the fact that the lambda only accesses width & height, it looks like a change to any property triggers re-evaluation. I'm kind of hoping it works this way, bad for efficiency, good for understanding!

                          • If it does not get called then somehow Qt has figured out that the lambda accesses only certain variables/properties, and I'm not sure how it dos that from code.

                          1 Reply Last reply
                          0
                          • J.HilkJ J.Hilk

                            @dheerendra

                            cough cough My voice is not my own:

                            The setBinding function itself doesn't directly analyze the lambda body or "know" about the variables width and height. Instead, the QProperty class provides a mechanism for registering dependencies between properties.

                            When you call setBinding, you're essentially telling the QProperty object that the value of this property (area in your case) depends on the values of other properties, namely width and height.

                            The lambda expression you provide is a function that calculates the value of the area property based on the values of width and height. However, it's not the lambda expression itself that the QProperty object "understands" or keeps track of; it's the fact that you've registered a dependency on width and height.

                            Internally, when you call setBinding, the QProperty object can inspect the lambda expression and identify any external variables that are captured by reference. In your lambda & { return width * height; }, width and height are captured by reference (&), indicating that they are external variables used inside the lambda body.

                            Once the QProperty object identifies these external variables, it stores them as dependencies for the property. So, whenever the values of these dependencies change (i.e., when width or height changes), the QProperty object knows that it needs to re-evaluate the binding function associated with the property.

                            In essence, the QProperty class provides a mechanism for tracking dependencies between properties based on the information you provide when you set up bindings. It doesn't directly analyze the lambda body or "understand" the variables used inside it; it simply keeps track of the dependencies you specify.

                            GrecKoG Offline
                            GrecKoG Offline
                            GrecKo
                            Qt Champions 2018
                            wrote on last edited by GrecKo
                            #12

                            @J-Hilk said in C++ QProperty binding Question:

                            Internally, when you call setBinding, the QProperty object can inspect the lambda expression and identify any external variables that are captured by reference. In your lambda & { return width * height; }, width and height are captured by reference (&), indicating that they are external variables used inside the lambda body.

                            No.

                            The QProperty knows its dependency because when you call setBinding with a lambda, the lambda is executed and it tracks the other properties that are being evaluated in it.

                            If both width and height are QProperty<int>.
                            width * height is first calling the implicit QProperty<int>::operator int() for both, converting them to int so it can call the arithmetic operator * on their values. This operator int() is what is registering the dependency.

                            To put it otherwise, when calling area.setBinding([&](){ return width * height; }); here is what happens:

                            • the lambda is stored in the area QProperty to be called later.
                            • area is marked as the current property being evaluated.
                            • the lambda is then executed.
                              • width is being accessed through its conversion operator, it is thus being registered as a dependency of the currently evaluated property (area here)
                              • the same happens for height
                            • the return value of the lambda is assigned to area
                            • area is no longer marked as the currently evaluated property.

                            After that, every time that width and height are changed, the lambda is being reevaluated and the above process redone.

                            JonBJ dheerendraD 2 Replies Last reply
                            3
                            • GrecKoG GrecKo

                              @J-Hilk said in C++ QProperty binding Question:

                              Internally, when you call setBinding, the QProperty object can inspect the lambda expression and identify any external variables that are captured by reference. In your lambda & { return width * height; }, width and height are captured by reference (&), indicating that they are external variables used inside the lambda body.

                              No.

                              The QProperty knows its dependency because when you call setBinding with a lambda, the lambda is executed and it tracks the other properties that are being evaluated in it.

                              If both width and height are QProperty<int>.
                              width * height is first calling the implicit QProperty<int>::operator int() for both, converting them to int so it can call the arithmetic operator * on their values. This operator int() is what is registering the dependency.

                              To put it otherwise, when calling area.setBinding([&](){ return width * height; }); here is what happens:

                              • the lambda is stored in the area QProperty to be called later.
                              • area is marked as the current property being evaluated.
                              • the lambda is then executed.
                                • width is being accessed through its conversion operator, it is thus being registered as a dependency of the currently evaluated property (area here)
                                • the same happens for height
                              • the return value of the lambda is assigned to area
                              • area is no longer marked as the currently evaluated property.

                              After that, every time that width and height are changed, the lambda is being reevaluated and the above process redone.

                              JonBJ Offline
                              JonBJ Offline
                              JonB
                              wrote on last edited by
                              #13

                              @GrecKo said in C++ QProperty binding Question:

                              width * height is first calling the implicit QProperty<int>::operator int() for both, converting them to int so it can call the arithmetic operator * on their values. This operator int() is what is registering the dependency.

                              [My italics.] Wow! OK, that answers the question as to how it gets at the dependencies without "analyzing" code, which it couldn't really do from C++. But that means there must be this or an equivalent for every possible operation you could do on a QProperty. Makes you wonder if you find some expression involving a QProperty which cannot be "tracked" like this, but I guess not.

                              1 Reply Last reply
                              1
                              • GrecKoG GrecKo

                                @J-Hilk said in C++ QProperty binding Question:

                                Internally, when you call setBinding, the QProperty object can inspect the lambda expression and identify any external variables that are captured by reference. In your lambda & { return width * height; }, width and height are captured by reference (&), indicating that they are external variables used inside the lambda body.

                                No.

                                The QProperty knows its dependency because when you call setBinding with a lambda, the lambda is executed and it tracks the other properties that are being evaluated in it.

                                If both width and height are QProperty<int>.
                                width * height is first calling the implicit QProperty<int>::operator int() for both, converting them to int so it can call the arithmetic operator * on their values. This operator int() is what is registering the dependency.

                                To put it otherwise, when calling area.setBinding([&](){ return width * height; }); here is what happens:

                                • the lambda is stored in the area QProperty to be called later.
                                • area is marked as the current property being evaluated.
                                • the lambda is then executed.
                                  • width is being accessed through its conversion operator, it is thus being registered as a dependency of the currently evaluated property (area here)
                                  • the same happens for height
                                • the return value of the lambda is assigned to area
                                • area is no longer marked as the currently evaluated property.

                                After that, every time that width and height are changed, the lambda is being reevaluated and the above process redone.

                                dheerendraD Offline
                                dheerendraD Offline
                                dheerendra
                                Qt Champions 2022
                                wrote on last edited by
                                #14

                                @GrecKo said in C++ QProperty binding Question:

                                the lambda is then executed.

                                Thanks GrecKo. This clears my thought process. Lambda is getting executed the moment you do the setBinding.

                                Dheerendra
                                @Community Service
                                Certified Qt Specialist
                                http://www.pthinks.com

                                1 Reply Last reply
                                1
                                • dheerendraD dheerendra has marked this topic as solved on

                                • Login

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