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. How to write a self contained editor in QML (like C++ implemented CheckBox is)
Forum Update on Monday, May 27th 2025

How to write a self contained editor in QML (like C++ implemented CheckBox is)

Scheduled Pinned Locked Moved Solved QML and Qt Quick
9 Posts 3 Posters 499 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.
  • M Offline
    M Offline
    monsieurgustav
    wrote on last edited by
    #1

    I try to write MyCheckBox in QML that can be used the same as a Controls2 CheckBox.

    An obvious solution is something like:

    Rectangle {
      id: root
      property bool checked
      color: checked ? 'black' : 'red'
      MouseArea {
        anchors.fill: parent
        onClicked: root.checked = !root.checked
      }
    }
    

    But if the parent binds the "checked" property to anything, the binding breaks because of the assignment in the onClicked handler.

    Item {
      property bool allow: true
      MyCheckBox {
        checked: allow
        onCheckedChanged: allow = checked
      }
    }
    

    In the above code, using Controls2 CheckBox instead of MyCheckBox works as expected. (because on the c++ side, there is a better control how to manage bindings)

    The only alternative I found is to define a new signal in MyCheckBox "checkedEdited(bool newChecked)", trigger that signal (instead of the assignment to "checked") and listen to it in the parent to update "allow", that will in turn update "checked".

    I find this "solution" really bad:

    • MyCheckBox is unable to update its own value now: it relies on the parent doing its job,
    • The parent has to know about this alternate signal, instead of the obvious onCheckedChanged.
    • Because Controls2 is used as well, one must figure every time what's the correct way of binding stuff, also making refactoring (replacing CheckBox by MyCheckBox) very frustrating.

    Does anyone has a simple recipe, that does not add burden to the parent?

    KroMignonK 1 Reply Last reply
    0
    • M monsieurgustav

      I try to write MyCheckBox in QML that can be used the same as a Controls2 CheckBox.

      An obvious solution is something like:

      Rectangle {
        id: root
        property bool checked
        color: checked ? 'black' : 'red'
        MouseArea {
          anchors.fill: parent
          onClicked: root.checked = !root.checked
        }
      }
      

      But if the parent binds the "checked" property to anything, the binding breaks because of the assignment in the onClicked handler.

      Item {
        property bool allow: true
        MyCheckBox {
          checked: allow
          onCheckedChanged: allow = checked
        }
      }
      

      In the above code, using Controls2 CheckBox instead of MyCheckBox works as expected. (because on the c++ side, there is a better control how to manage bindings)

      The only alternative I found is to define a new signal in MyCheckBox "checkedEdited(bool newChecked)", trigger that signal (instead of the assignment to "checked") and listen to it in the parent to update "allow", that will in turn update "checked".

      I find this "solution" really bad:

      • MyCheckBox is unable to update its own value now: it relies on the parent doing its job,
      • The parent has to know about this alternate signal, instead of the obvious onCheckedChanged.
      • Because Controls2 is used as well, one must figure every time what's the correct way of binding stuff, also making refactoring (replacing CheckBox by MyCheckBox) very frustrating.

      Does anyone has a simple recipe, that does not add burden to the parent?

      KroMignonK Offline
      KroMignonK Offline
      KroMignon
      wrote on last edited by KroMignon
      #2

      @monsieurgustav I think the problem is your Item definition.

      I would change it to:

      Item {
        property alias allow: _chkBox.checked
        MyCheckBox {
          id: _chkBox
          checked: true
        }
      }
      

      This will avoid binding loop

      It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

      1 Reply Last reply
      0
      • M Offline
        M Offline
        monsieurgustav
        wrote on last edited by
        #3

        True. But it does not work if there are multiple "editors" for the same value.

        Item {
          property alias allow: _chkBox.checked
          MyCheckBox {
            id: _chkBox
            checked: true
          }
          MyOtherKindOfCheckBox {
            ???
          }
        }
        
        KroMignonK 1 Reply Last reply
        0
        • GabrielRRG Offline
          GabrielRRG Offline
          GabrielRR
          wrote on last edited by GabrielRR
          #4

          hello, if you are trying to set from your parent went to allow the checked property to swap from true/false maybe you could try something like this:

          Rectangle {
              id: root
              property bool checked
              property bool allow: true
              color: checked ? 'black' : 'red'
              MouseArea {
                  anchors.fill: parent
                  onClicked: {
                      root.checked = root.allow ? !root.checked : root.checked
                  }
              }
          }
          
          Item {
           id: parentRoot
            property bool allow: true
            MyCheckBox {
              id: checkBox
              checked: allow
              onCheckedChanged: parentRoot.allow = checkBox.allow
            }
          }
          

          With this:

          • MyCheckBox is unable to update its own value now: it relies on the parent doing its job
            R/we no longer relies on the parent to update its own value.
          • The parent has to know about this alternate signal, instead of the obvious onCheckedChanged.
            R/ We no longer need to use another signal and we can check onChckedChanged if needed.
          • Because Controls2 is used as well, one must figure every time what's the correct way of binding stuff, also making refactoring (replacing CheckBox by MyCheckBox) very frustrating.
            R/ The allow property in the checkBox object will now only be modified if there is an special need on each object you require the checkBox and will no longer depend on any parent handling the check property.

          Lic-Ing. Jose Gabriel Lopez Villalobos
          Embedded Software Engineer
          RidgeRun Engineering Ltd.
          www.ridgerun.com
          Email: gabriel.lopez@ridgerun.com

          M 1 Reply Last reply
          0
          • M monsieurgustav

            True. But it does not work if there are multiple "editors" for the same value.

            Item {
              property alias allow: _chkBox.checked
              MyCheckBox {
                id: _chkBox
                checked: true
              }
              MyOtherKindOfCheckBox {
                ???
              }
            }
            
            KroMignonK Offline
            KroMignonK Offline
            KroMignon
            wrote on last edited by
            #5

            @monsieurgustav said in How to write a self contained editor in QML (like C++ implemented CheckBox is):

            True. But it does not work if there are multiple "editors" for the same value.

            Okay, it seems I don't really understand what your use case is.
            Can you explain what the final goal is?

            It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

            1 Reply Last reply
            0
            • GabrielRRG GabrielRR

              hello, if you are trying to set from your parent went to allow the checked property to swap from true/false maybe you could try something like this:

              Rectangle {
                  id: root
                  property bool checked
                  property bool allow: true
                  color: checked ? 'black' : 'red'
                  MouseArea {
                      anchors.fill: parent
                      onClicked: {
                          root.checked = root.allow ? !root.checked : root.checked
                      }
                  }
              }
              
              Item {
               id: parentRoot
                property bool allow: true
                MyCheckBox {
                  id: checkBox
                  checked: allow
                  onCheckedChanged: parentRoot.allow = checkBox.allow
                }
              }
              

              With this:

              • MyCheckBox is unable to update its own value now: it relies on the parent doing its job
                R/we no longer relies on the parent to update its own value.
              • The parent has to know about this alternate signal, instead of the obvious onCheckedChanged.
                R/ We no longer need to use another signal and we can check onChckedChanged if needed.
              • Because Controls2 is used as well, one must figure every time what's the correct way of binding stuff, also making refactoring (replacing CheckBox by MyCheckBox) very frustrating.
                R/ The allow property in the checkBox object will now only be modified if there is an special need on each object you require the checkBox and will no longer depend on any parent handling the check property.
              M Offline
              M Offline
              monsieurgustav
              wrote on last edited by
              #6

              @GabrielRR said in How to write a self contained editor in QML (like C++ implemented CheckBox is):

              root.checked = root.allow ? !root.checked : root.checked

              I think the "checked " binding the broken after this assignment.

              1 Reply Last reply
              0
              • M Offline
                M Offline
                monsieurgustav
                wrote on last edited by
                #7

                @KroMignon Currently, I try to write code that display/edit the same underlying data (double) to different editors in the same page. I managed to do it but it is not straight forward.

                I'd like to reach the same simplicity achieved in:

                        property bool test: true
                        CheckBox {
                            anchors.centerIn: parent
                            anchors.verticalCenterOffset: 0
                            checked: parent.test
                            onCheckedChanged: parent.test = checked
                        }
                        CheckBox {
                            anchors.centerIn: parent
                            anchors.verticalCenterOffset: 50
                            checked: parent.test
                            onCheckedChanged: parent.test = checked
                        }
                

                The above code works, no binding is broken at any time, and it is simple: only "checked" and the obvious "onCheckedChanged" are needed from the outside.

                KroMignonK 1 Reply Last reply
                0
                • M monsieurgustav

                  @KroMignon Currently, I try to write code that display/edit the same underlying data (double) to different editors in the same page. I managed to do it but it is not straight forward.

                  I'd like to reach the same simplicity achieved in:

                          property bool test: true
                          CheckBox {
                              anchors.centerIn: parent
                              anchors.verticalCenterOffset: 0
                              checked: parent.test
                              onCheckedChanged: parent.test = checked
                          }
                          CheckBox {
                              anchors.centerIn: parent
                              anchors.verticalCenterOffset: 50
                              checked: parent.test
                              onCheckedChanged: parent.test = checked
                          }
                  

                  The above code works, no binding is broken at any time, and it is simple: only "checked" and the obvious "onCheckedChanged" are needed from the outside.

                  KroMignonK Offline
                  KroMignonK Offline
                  KroMignon
                  wrote on last edited by
                  #8

                  @monsieurgustav said in How to write a self contained editor in QML (like C++ implemented CheckBox is):

                  The above code works, no binding is broken at any time, and it is simple: only "checked" and the obvious "onCheckedChanged" are needed from the outside.

                  Okay, now I understand, but I have no idea how to do it in QML.
                  In C++ there is no problem to do this, because Q_PROPERTY gives you more freedom.

                  It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

                  1 Reply Last reply
                  0
                  • M Offline
                    M Offline
                    monsieurgustav
                    wrote on last edited by
                    #9

                    OK, I found a way, the result is quite nice. But it's going to be a little bit dirty... :)

                    This works as I wanted, no binding is broken:

                    property bool test: true
                    MyCheckBox {
                      anchors.centerIn: parent
                      anchors.verticalCenterOffset: 0
                      checked: parent.test
                      onCheckedChanged: parent.test = checked
                    }
                    MyCheckBox {
                      anchors.centerIn: parent
                      anchors.verticalCenterOffset: 50
                      checked: parent.test
                      onCheckedChanged: parent.test = checked
                    }
                    

                    MyCheckBox.qml

                    Rectangle {
                      id: root
                      property bool checked
                      color: checked ? 'black' : 'red'
                      MouseArea {
                        anchors.fill: parent
                        onClicked: QmlPropertyUtils.setValueKeepBinding(root, "checked", !root.checked)
                      }
                    }
                    

                    In c++, declare a singleton (qmlRegisterSingletonInstance) with this function:

                    #include <QQmlProperty>
                    #include <private/qqmlproperty_p.h>
                    #include <private/qqmlpropertydata_p.h>
                    
                    void QmlPropertyUtils::setValueKeepBinding(QJSValue object, QString propertyName, QVariant value)
                    {
                        if (!object.isQObject())
                        {
                            qWarning() << object.toString() << "is not an qobject";
                            return;
                        }
                    
                        auto qobject = object.toQObject();
                        QQmlProperty property(qobject, propertyName);
                    
                        if (!property.isValid() || !property.isWritable())
                        {
                            qWarning() << propertyName << "is not a valid and write property";
                            return;
                        }
                    
                        if (QQmlPropertyPrivate::write(property, value, QQmlPropertyData::DontRemoveBinding))
                        {
                            qDebug() << "setValueKeepBinding(" << object.toString() << propertyName << value.toString() << ") succeeded";
                        }
                        else
                        {
                            qWarning() << "setValueKeepBinding(" << object.toString() << propertyName << value.toString() << ") failed";
                        }
                    }
                    

                    As you may have notice, it relies on private headers (hence the dirtiness...) so:

                    • you need to add them in the include search path.
                    • you better don't care about binary compatibility...
                    using cmake:
                    include_directories(${Qt${QT_VERSION_MAJOR}Quick_PRIVATE_INCLUDE_DIRS})
                    
                    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