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
Forum Updated to NodeBB v4.3 + New Features

Dynamic generation of ListView content

Scheduled Pinned Locked Moved Solved QML and Qt Quick
5 Posts 2 Posters 2.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.
  • E Offline
    E Offline
    Elliott
    wrote on 2 Oct 2017, 16:38 last edited by Elliott 10 Feb 2017, 20:55
    #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 2 Oct 2017, 19:44
    0
    • E Elliott
      2 Oct 2017, 16:38

      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 2 Oct 2017, 19:44 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 2 Oct 2017, 20:56
      0
      • E Eeli K
        2 Oct 2017, 19:44

        @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 2 Oct 2017, 20:56 last edited by Elliott 10 Feb 2017, 20:56
        #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
          2 Oct 2017, 16:38

          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 3 Oct 2017, 09:54 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 3 Oct 2017, 12:51
          0
          • E Eeli K
            3 Oct 2017, 09:54

            @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 3 Oct 2017, 12:51 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

            1/5

            2 Oct 2017, 16:38

            • Login

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