Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt
  • Unsolved
Collapse
qtws26_logo

The Qt Event of the Year: Qt World Summit 2026

Save Your Spot >
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. How to create dynamic bindings in ListModel?
Qt 6.12 LTS is out! See what's new in the release blog

How to create dynamic bindings in ListModel?

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
6 Posts 3 Posters 1.8k 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.
  • K Offline
    K Offline
    Kamichanw
    wrote on last edited by
    #1

    In small example below, I'm trying to create rectangles whose width depends on foo. As we all know, we cannot use property binding in ListElement because ListElement doesn't allow to use script for property value.

    import QtQuick 2.0
    import QtQuick.Controls
    
    Window {
        width: 400
        height: 300
        visible: true
        property int foo: 10
    
        ListModel {
            id: listModel
            // ListElement {
            //     width: foo // error: ListElement: cannot use script for property value
            // }
        }
    
        Row {
            anchors.top: parent.top
            Repeater {
                id: repeater
                model: listModel
    
                delegate: Rectangle {
                    width: model.width
                    height: 50
                    color: "green"
                }
            }
        }
        Button {
            text: "add item"
            anchors.top: parent.top
            anchors.horizontalCenter: parent.horizontalCenter
            onClicked: {
                listModel.append({
                                     "width": foo // works, but is not a binding
                                 })
            }
        }
    }
    
    

    In order to use script, I have to try to append in function. However, in this way, if foo is changed somewhere, the width of rectangles won't change accordingly. So anyone knows a better solution?

    B GrecKoG 2 Replies Last reply
    0
    • K Kamichanw

      In small example below, I'm trying to create rectangles whose width depends on foo. As we all know, we cannot use property binding in ListElement because ListElement doesn't allow to use script for property value.

      import QtQuick 2.0
      import QtQuick.Controls
      
      Window {
          width: 400
          height: 300
          visible: true
          property int foo: 10
      
          ListModel {
              id: listModel
              // ListElement {
              //     width: foo // error: ListElement: cannot use script for property value
              // }
          }
      
          Row {
              anchors.top: parent.top
              Repeater {
                  id: repeater
                  model: listModel
      
                  delegate: Rectangle {
                      width: model.width
                      height: 50
                      color: "green"
                  }
              }
          }
          Button {
              text: "add item"
              anchors.top: parent.top
              anchors.horizontalCenter: parent.horizontalCenter
              onClicked: {
                  listModel.append({
                                       "width": foo // works, but is not a binding
                                   })
              }
          }
      }
      
      

      In order to use script, I have to try to append in function. However, in this way, if foo is changed somewhere, the width of rectangles won't change accordingly. So anyone knows a better solution?

      B Offline
      B Offline
      Bob64
      wrote on last edited by
      #2

      @Kamichanw you could use setProperty to update your model values. Do this in a function that you call from a on<Property>Changed handler or use a Connection, whatever makes more sense for your use case.

      1 Reply Last reply
      0
      • K Kamichanw

        In small example below, I'm trying to create rectangles whose width depends on foo. As we all know, we cannot use property binding in ListElement because ListElement doesn't allow to use script for property value.

        import QtQuick 2.0
        import QtQuick.Controls
        
        Window {
            width: 400
            height: 300
            visible: true
            property int foo: 10
        
            ListModel {
                id: listModel
                // ListElement {
                //     width: foo // error: ListElement: cannot use script for property value
                // }
            }
        
            Row {
                anchors.top: parent.top
                Repeater {
                    id: repeater
                    model: listModel
        
                    delegate: Rectangle {
                        width: model.width
                        height: 50
                        color: "green"
                    }
                }
            }
            Button {
                text: "add item"
                anchors.top: parent.top
                anchors.horizontalCenter: parent.horizontalCenter
                onClicked: {
                    listModel.append({
                                         "width": foo // works, but is not a binding
                                     })
                }
            }
        }
        
        

        In order to use script, I have to try to append in function. However, in this way, if foo is changed somewhere, the width of rectangles won't change accordingly. So anyone knows a better solution?

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

        @Kamichanw My first instinct would be to not do that.

        The philosophy I adhere to when thinking about QML is that the QML objects are a representation of my data, and a way to interact with it. They are not my data.

        In your case what does the width of your rectangle represents?

        Some time ago I had to develop a UI editor in QML, in this case the state of the UI and where elements were placed was my data.
        It was provided as a model and represented by Rectangle delegates.
        The delegates where placed according to the model data and when I resized a Rectangle it actually modified the underlying data and the delegate would then update. I never modified my QML items directly, everything was in a model.

        Here's a video of its PoC : https://gfycat.com/scholarlythosefly

        K 1 Reply Last reply
        1
        • GrecKoG GrecKo

          @Kamichanw My first instinct would be to not do that.

          The philosophy I adhere to when thinking about QML is that the QML objects are a representation of my data, and a way to interact with it. They are not my data.

          In your case what does the width of your rectangle represents?

          Some time ago I had to develop a UI editor in QML, in this case the state of the UI and where elements were placed was my data.
          It was provided as a model and represented by Rectangle delegates.
          The delegates where placed according to the model data and when I resized a Rectangle it actually modified the underlying data and the delegate would then update. I never modified my QML items directly, everything was in a model.

          Here's a video of its PoC : https://gfycat.com/scholarlythosefly

          K Offline
          K Offline
          Kamichanw
          wrote on last edited by
          #4

          @GrecKo Your point is so elegant, especially when we need to change a lot of data in ListModel, but I still have some scenarios that make me have to change ListModel slightly and in low cost. For example, when I develope a maximize/restore button on title bar, I hope the icon url can be changed dynamically according to the visiblity of Window. My solution is use Qt.binding() in js funcion.

          icon = Qt.binding(() => wnd.visibility === Window.Maximized ? "qrc:/icons/restore.svg" : "qrc:/icons/maximize.svg")
          

          For the scenario in the question, we can

          // other code...
              Button {
                  text: "add item"
                  anchors.top: parent.top
                  anchors.horizontalCenter: parent.horizontalCenter
                  onClicked: {
                      listModel.append({
                                           "width": foo
                                       })
                      listModel.get(0).width = Qt.binding(() => return foo)
                  }
              }
          // other code...
          
          GrecKoG 1 Reply Last reply
          0
          • K Kamichanw

            @GrecKo Your point is so elegant, especially when we need to change a lot of data in ListModel, but I still have some scenarios that make me have to change ListModel slightly and in low cost. For example, when I develope a maximize/restore button on title bar, I hope the icon url can be changed dynamically according to the visiblity of Window. My solution is use Qt.binding() in js funcion.

            icon = Qt.binding(() => wnd.visibility === Window.Maximized ? "qrc:/icons/restore.svg" : "qrc:/icons/maximize.svg")
            

            For the scenario in the question, we can

            // other code...
                Button {
                    text: "add item"
                    anchors.top: parent.top
                    anchors.horizontalCenter: parent.horizontalCenter
                    onClicked: {
                        listModel.append({
                                             "width": foo
                                         })
                        listModel.get(0).width = Qt.binding(() => return foo)
                    }
                }
            // other code...
            
            GrecKoG Offline
            GrecKoG Offline
            GrecKo
            Qt Champions 2018
            wrote on last edited by GrecKo
            #5

            @Kamichanw https://doc.qt.io/qt-6/qml-qtqml-models-listmodel.html#get-method

            Warning: The returned object is not guaranteed to remain valid. It should not be used in property bindings.

            for the icon you can do a declarative binding, no need for Qt.binding.

            Without more context we can't really help you. The code you pasted is not something that I would find good.

            When is foo modified and why can't you modify the model instead?
            If you don't want that to be in a model why don't you bind to width: foo in your delegates instead?

            K 1 Reply Last reply
            0
            • GrecKoG GrecKo

              @Kamichanw https://doc.qt.io/qt-6/qml-qtqml-models-listmodel.html#get-method

              Warning: The returned object is not guaranteed to remain valid. It should not be used in property bindings.

              for the icon you can do a declarative binding, no need for Qt.binding.

              Without more context we can't really help you. The code you pasted is not something that I would find good.

              When is foo modified and why can't you modify the model instead?
              If you don't want that to be in a model why don't you bind to width: foo in your delegates instead?

              K Offline
              K Offline
              Kamichanw
              wrote on last edited by
              #6

              @GrecKo Well, here is the thing. I'm writing a custom title bar, which enables users to add new buttons. I use Repeater whose model is a ListModel to generate buttons. In order to specify behaviors of onClicked, onContainsMouseChanged and onContainsPressChanged, I also maintain a list of object called callbacks in Repeater. When I intent to add maximize/restore button

              title.appendButton({
                  "name": "Maximize",
                  "icon": "qrc:/icons/maximize.svg",
                  "visible": Boolean(titleButton & ShadowWindow.TitleButton.Maximize),
                  "tooltip": "Maximize"
                  }, button => {
                      button.icon.source = Qt.binding(() =>  control.visibility === Window.Maximized ? "qrc:\icons\restore.svg" : "qrc:\icons\maximize.svg")
                      button.toolTip.text = Qt.binding(() => control.visibility === Window.Maximized ? "Restore" : "Maximize")
                      if (control.visibility === Window.Maximized)
                                control.showNormal()
                      else
                                control.showMaximized()
                      })
              

              As you can see, I set Qt.binding in onClicked. Do you think it is a good way to set toolTip.text and icon.source directly in onClicked? Like this

              if (control.visibility === Window.Maximized) {
                  button.toolTip.text = "Maximize"
                  button.icon.source = "qrc:/icons/maximize.svg"
                  control.showNormal()
              } else {
                   button.toolTip.text = "Restore"
                   button.icon.source = "qrc:/icons/restore.svg"
                   control.showMaximized()
              }
              

              Besides, I still have a problem. I encapsulated a series of initialization in the init() function. Due to uncertainty of order of Component completion, I have to make user call init() at the beginning of their Component.onCompleted, do you have a better solution?

              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
              • Unsolved