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. Dynamic generation of ListView content

Dynamic generation of ListView content

Scheduled Pinned Locked Moved Solved QML and Qt Quick
5 Posts 2 Posters 2.9k 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.
  • E Offline
    E Offline
    Elliott
    wrote on last edited by Elliott
    #1

    Hi all,

    I've got a QML application and I'm trying to fill in a ListView with data pulled from a SQL database (in C++). Getting data works fine, but creating a ListView with an arbitrary number of entries is being problematic. I've been searching the web for this and have seen a lot of ways of doing this, which are variably complicated and weird. What I settled on is this:

    import QtQuick 2.7
    import QtQuick.Controls 2.2
    import QtQml 2.2
    import QtQml.Models 2.3
    
    Item
    {
        z: 3
        visible: false
    
        height: 680
        width: 800
    
        property int iRowCount: 7
        property int ixRowCounter: 1
    
        Text
        {
            id: lblTitle
            anchors.top: parent.top
            anchors.topMargin: 10
            anchors.left: parent.left
            anchors.leftMargin: 10
            text: "Choose flavors:"
            font.pointSize: 20
            horizontalAlignment: Text.AlignLeft
        }
    
        Rectangle
        {
            id: yoMenuContainer
            anchors.left: parent.left
            anchors.leftMargin: 10
            anchors.right: parent.right
            anchors.rightMargin: 10
            anchors.top: lblTitle.bottom
            anchors.topMargin: 5
            border.width: 1
            height: 400
    
            ListModel
            {
                id: yoListModel
                ListElement
                {
                    sqlID: 0
                }
            }
    
            ListView
            {
                id: yoListView
                anchors.fill: parent
                model: yoListModel
    
                delegate: yoDelegate
                clip: true
            }
    
            Component
            {
                id: yoDelegate
    
                Item
                {
                    id: yoItem
    
                    Component.onCompleted:
                    {
                        var component = Qt.createComponent("YoMenuRow.qml");
    
                        if(ixRowCounter <= iRowCount)
                        {
                            yoListModel.append({"sqlID": ixRowCounter});
                            if(component.status === Component.Ready)
                            {
                                var object = component.createObject(yoItem, {"id": "yoRow"+ixRowCounter});
                            }
                            object.y = object.height * (ixRowCounter - 1);
                            ixRowCounter++;
                        }
                    }
                }
            }
        }
    }
    

    ... the referenced YoMenuRow.qml file:

    import QtQuick 2.7
    import QtQuick.Controls 2.2
    
    Row
    {
        id: yoRow
        spacing: 30
        height: 100
        bottomPadding: 5
        CheckBox
        {
            anchors.verticalCenter: parent.verticalCenter
            onCheckStateChanged:
            {
                console.log("Checked box for id " + sqlID);
            }
        }
        Image
        {
            source: "/img/img-entry-64.png"
        }
        Text
        {
            text: "This entry"
            anchors.verticalCenter: parent.verticalCenter
            font.pointSize: 20
        }
    }
    

    ... as you can see, I'm not even attempting the SQL stuff at this point, I just want a ListView with an arbitrary number of lines generated when the page loads. This code does that just fine, and I have some placeholder code that loops through and creates some number of entries (iRowCount, currently 7). I get 7 entries, BUT the flickable part is broken.

    The behavior I get now is that when the screen appears, I have all 7 entries. If I pull DOWN on the list (so beyond the starting point), it behaves fine - it snaps back when I let go. If I pull UP, to see entries farther down, the entire list disappears. It behaves a bit like it's trying to scroll, but at light speed so the entire list snaps out of view instantly. If I let go, it snaps back to the first list item.

    I've done various things that have changed this behavior slightly, but never to a useful degree. If I remove the Component.onCompleted stuff and just put in 7 Rows, the Flickable part works fine, so in theory the basic setup of the ListView is right, just the Component part is breaking it.

    Any suggestions on what I can try here? I get the feeling that when I'm creating components, something - a size, or index, or position - is just getting off, and if I fix that I'll be good. That's my hope, anyway!

    Thanks!

    E 2 Replies Last reply
    0
    • E Elliott

      Hi all,

      I've got a QML application and I'm trying to fill in a ListView with data pulled from a SQL database (in C++). Getting data works fine, but creating a ListView with an arbitrary number of entries is being problematic. I've been searching the web for this and have seen a lot of ways of doing this, which are variably complicated and weird. What I settled on is this:

      import QtQuick 2.7
      import QtQuick.Controls 2.2
      import QtQml 2.2
      import QtQml.Models 2.3
      
      Item
      {
          z: 3
          visible: false
      
          height: 680
          width: 800
      
          property int iRowCount: 7
          property int ixRowCounter: 1
      
          Text
          {
              id: lblTitle
              anchors.top: parent.top
              anchors.topMargin: 10
              anchors.left: parent.left
              anchors.leftMargin: 10
              text: "Choose flavors:"
              font.pointSize: 20
              horizontalAlignment: Text.AlignLeft
          }
      
          Rectangle
          {
              id: yoMenuContainer
              anchors.left: parent.left
              anchors.leftMargin: 10
              anchors.right: parent.right
              anchors.rightMargin: 10
              anchors.top: lblTitle.bottom
              anchors.topMargin: 5
              border.width: 1
              height: 400
      
              ListModel
              {
                  id: yoListModel
                  ListElement
                  {
                      sqlID: 0
                  }
              }
      
              ListView
              {
                  id: yoListView
                  anchors.fill: parent
                  model: yoListModel
      
                  delegate: yoDelegate
                  clip: true
              }
      
              Component
              {
                  id: yoDelegate
      
                  Item
                  {
                      id: yoItem
      
                      Component.onCompleted:
                      {
                          var component = Qt.createComponent("YoMenuRow.qml");
      
                          if(ixRowCounter <= iRowCount)
                          {
                              yoListModel.append({"sqlID": ixRowCounter});
                              if(component.status === Component.Ready)
                              {
                                  var object = component.createObject(yoItem, {"id": "yoRow"+ixRowCounter});
                              }
                              object.y = object.height * (ixRowCounter - 1);
                              ixRowCounter++;
                          }
                      }
                  }
              }
          }
      }
      

      ... the referenced YoMenuRow.qml file:

      import QtQuick 2.7
      import QtQuick.Controls 2.2
      
      Row
      {
          id: yoRow
          spacing: 30
          height: 100
          bottomPadding: 5
          CheckBox
          {
              anchors.verticalCenter: parent.verticalCenter
              onCheckStateChanged:
              {
                  console.log("Checked box for id " + sqlID);
              }
          }
          Image
          {
              source: "/img/img-entry-64.png"
          }
          Text
          {
              text: "This entry"
              anchors.verticalCenter: parent.verticalCenter
              font.pointSize: 20
          }
      }
      

      ... as you can see, I'm not even attempting the SQL stuff at this point, I just want a ListView with an arbitrary number of lines generated when the page loads. This code does that just fine, and I have some placeholder code that loops through and creates some number of entries (iRowCount, currently 7). I get 7 entries, BUT the flickable part is broken.

      The behavior I get now is that when the screen appears, I have all 7 entries. If I pull DOWN on the list (so beyond the starting point), it behaves fine - it snaps back when I let go. If I pull UP, to see entries farther down, the entire list disappears. It behaves a bit like it's trying to scroll, but at light speed so the entire list snaps out of view instantly. If I let go, it snaps back to the first list item.

      I've done various things that have changed this behavior slightly, but never to a useful degree. If I remove the Component.onCompleted stuff and just put in 7 Rows, the Flickable part works fine, so in theory the basic setup of the ListView is right, just the Component part is breaking it.

      Any suggestions on what I can try here? I get the feeling that when I'm creating components, something - a size, or index, or position - is just getting off, and if I fix that I'll be good. That's my hope, anyway!

      Thanks!

      E Offline
      E Offline
      Eeli K
      wrote on last edited by
      #2

      @Elliott Impossible to test (pasted to two qml files):

      qrc:/main.qml:55: ReferenceError: ixRowCounter is not defined
      qrc:/main.qml:22: ReferenceError: tStyle is not defined
      qrc:/main.qml:19: ReferenceError: tStyle is not defined
      qrc:/main.qml:17: ReferenceError: lblTitle is not defined
      

      Style can be changed ad hoc but please at least make the example self-contained with ixRowCounter and other possible crucial things.

      E 1 Reply Last reply
      0
      • E Eeli K

        @Elliott Impossible to test (pasted to two qml files):

        qrc:/main.qml:55: ReferenceError: ixRowCounter is not defined
        qrc:/main.qml:22: ReferenceError: tStyle is not defined
        qrc:/main.qml:19: ReferenceError: tStyle is not defined
        qrc:/main.qml:17: ReferenceError: lblTitle is not defined
        

        Style can be changed ad hoc but please at least make the example self-contained with ixRowCounter and other possible crucial things.

        E Offline
        E Offline
        Elliott
        wrote on last edited by Elliott
        #3

        @Eeli-K Whoops! Sorry, I was trying to cut out unnecessary stuff but got carried away. I edited the original post so the code should be more self-contained.

        1 Reply Last reply
        0
        • E Elliott

          Hi all,

          I've got a QML application and I'm trying to fill in a ListView with data pulled from a SQL database (in C++). Getting data works fine, but creating a ListView with an arbitrary number of entries is being problematic. I've been searching the web for this and have seen a lot of ways of doing this, which are variably complicated and weird. What I settled on is this:

          import QtQuick 2.7
          import QtQuick.Controls 2.2
          import QtQml 2.2
          import QtQml.Models 2.3
          
          Item
          {
              z: 3
              visible: false
          
              height: 680
              width: 800
          
              property int iRowCount: 7
              property int ixRowCounter: 1
          
              Text
              {
                  id: lblTitle
                  anchors.top: parent.top
                  anchors.topMargin: 10
                  anchors.left: parent.left
                  anchors.leftMargin: 10
                  text: "Choose flavors:"
                  font.pointSize: 20
                  horizontalAlignment: Text.AlignLeft
              }
          
              Rectangle
              {
                  id: yoMenuContainer
                  anchors.left: parent.left
                  anchors.leftMargin: 10
                  anchors.right: parent.right
                  anchors.rightMargin: 10
                  anchors.top: lblTitle.bottom
                  anchors.topMargin: 5
                  border.width: 1
                  height: 400
          
                  ListModel
                  {
                      id: yoListModel
                      ListElement
                      {
                          sqlID: 0
                      }
                  }
          
                  ListView
                  {
                      id: yoListView
                      anchors.fill: parent
                      model: yoListModel
          
                      delegate: yoDelegate
                      clip: true
                  }
          
                  Component
                  {
                      id: yoDelegate
          
                      Item
                      {
                          id: yoItem
          
                          Component.onCompleted:
                          {
                              var component = Qt.createComponent("YoMenuRow.qml");
          
                              if(ixRowCounter <= iRowCount)
                              {
                                  yoListModel.append({"sqlID": ixRowCounter});
                                  if(component.status === Component.Ready)
                                  {
                                      var object = component.createObject(yoItem, {"id": "yoRow"+ixRowCounter});
                                  }
                                  object.y = object.height * (ixRowCounter - 1);
                                  ixRowCounter++;
                              }
                          }
                      }
                  }
              }
          }
          

          ... the referenced YoMenuRow.qml file:

          import QtQuick 2.7
          import QtQuick.Controls 2.2
          
          Row
          {
              id: yoRow
              spacing: 30
              height: 100
              bottomPadding: 5
              CheckBox
              {
                  anchors.verticalCenter: parent.verticalCenter
                  onCheckStateChanged:
                  {
                      console.log("Checked box for id " + sqlID);
                  }
              }
              Image
              {
                  source: "/img/img-entry-64.png"
              }
              Text
              {
                  text: "This entry"
                  anchors.verticalCenter: parent.verticalCenter
                  font.pointSize: 20
              }
          }
          

          ... as you can see, I'm not even attempting the SQL stuff at this point, I just want a ListView with an arbitrary number of lines generated when the page loads. This code does that just fine, and I have some placeholder code that loops through and creates some number of entries (iRowCount, currently 7). I get 7 entries, BUT the flickable part is broken.

          The behavior I get now is that when the screen appears, I have all 7 entries. If I pull DOWN on the list (so beyond the starting point), it behaves fine - it snaps back when I let go. If I pull UP, to see entries farther down, the entire list disappears. It behaves a bit like it's trying to scroll, but at light speed so the entire list snaps out of view instantly. If I let go, it snaps back to the first list item.

          I've done various things that have changed this behavior slightly, but never to a useful degree. If I remove the Component.onCompleted stuff and just put in 7 Rows, the Flickable part works fine, so in theory the basic setup of the ListView is right, just the Component part is breaking it.

          Any suggestions on what I can try here? I get the feeling that when I'm creating components, something - a size, or index, or position - is just getting off, and if I fix that I'll be good. That's my hope, anyway!

          Thanks!

          E Offline
          E Offline
          Eeli K
          wrote on last edited by
          #4

          @Elliott I just can't understand either what you want to do or why you're doing it that way. To create delegate objects you don't need Component.onCompleted of the delegate or createObject/createComponent. Especially you shouldn't care about creating delegates and positioning inside the delegate that way. It's the list view which creates and positions delegate objects. You handle only the model.

          Here's a simplified app:

          import QtQuick 2.6
          import QtQuick.Controls 2.2
          
          ApplicationWindow {
              visible: true
              width: 640
              height: 480
          
              Item
              {
                  anchors.fill:parent
                  id: root
          
                  property int iRowCount: 7
          
                  Rectangle
                  {
                      id: yoMenuContainer
                      anchors.left: parent.left
                      anchors.leftMargin: 10
                      anchors.right: parent.right
                      anchors.rightMargin: 10
                      anchors.top: lblTitle.bottom
                      anchors.topMargin: 5
                      border.width: 1
                      height: 400
          
                      //model is handled here for convenience, finally it would be in c++
                      // and triggered by whatever is suitable for the app
                      Component.onCompleted:
                      {
                          // iRowCount is in the root item but for testing could be hardcoded here as well
                          for (var rowCounter = 0; rowCounter < root.iRowCount; rowCounter++) {
                              yoListModel.append({"sqlID": rowCounter});
                          }
                      }
          
                      ListModel
                      {
                          id: yoListModel
                      }
          
                      ListView
                      {
                          id: yoListView
                          anchors.fill: parent
                          model: yoListModel
          
                          delegate: YoMenuRow{} //No createComponent! No positioning!
                          clip: true
                      }
                  }
              }
          }
          
          E 1 Reply Last reply
          0
          • E Eeli K

            @Elliott I just can't understand either what you want to do or why you're doing it that way. To create delegate objects you don't need Component.onCompleted of the delegate or createObject/createComponent. Especially you shouldn't care about creating delegates and positioning inside the delegate that way. It's the list view which creates and positions delegate objects. You handle only the model.

            Here's a simplified app:

            import QtQuick 2.6
            import QtQuick.Controls 2.2
            
            ApplicationWindow {
                visible: true
                width: 640
                height: 480
            
                Item
                {
                    anchors.fill:parent
                    id: root
            
                    property int iRowCount: 7
            
                    Rectangle
                    {
                        id: yoMenuContainer
                        anchors.left: parent.left
                        anchors.leftMargin: 10
                        anchors.right: parent.right
                        anchors.rightMargin: 10
                        anchors.top: lblTitle.bottom
                        anchors.topMargin: 5
                        border.width: 1
                        height: 400
            
                        //model is handled here for convenience, finally it would be in c++
                        // and triggered by whatever is suitable for the app
                        Component.onCompleted:
                        {
                            // iRowCount is in the root item but for testing could be hardcoded here as well
                            for (var rowCounter = 0; rowCounter < root.iRowCount; rowCounter++) {
                                yoListModel.append({"sqlID": rowCounter});
                            }
                        }
            
                        ListModel
                        {
                            id: yoListModel
                        }
            
                        ListView
                        {
                            id: yoListView
                            anchors.fill: parent
                            model: yoListModel
            
                            delegate: YoMenuRow{} //No createComponent! No positioning!
                            clip: true
                        }
                    }
                }
            }
            
            E Offline
            E Offline
            Elliott
            wrote on last edited by
            #5

            @Eeli-K That is perfect! The code I had was getting progressively more complex and weird because what I started with wasn't working, and I was trying progressively more desperate things. Having object.y = object.height * (ixRowCounter - 1); in particular seemed like a warning sign that things had gotten out of hand. This code is working exactly like I needed. Thanks!

            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