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. [Solved] Not all properties from ListModel are being made available to delegate

[Solved] Not all properties from ListModel are being made available to delegate

Scheduled Pinned Locked Moved QML and Qt Quick
qmlmodelslistmodellistview
5 Posts 2 Posters 7.0k 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.
  • E Offline
    E Offline
    eLim
    wrote on 8 Jul 2015, 06:19 last edited by eLim
    #1

    Hi. I currently have a ListView with a ListModel that uses a Loader for the delegate.

    in the Loader I have the following:

    onLoaded: {
        item.modelData = model
    }
    

    Every Component that the delegate can use as its source has the modelData property.
    When I add the following item to the list using the insert command:

     storiesModel.insert(insertIndex, { elementType: "imageelement", img: imgid })
    

    I am able to access that "img" property from inside the delegate without any issue at all, using the following:

     imgId: modelData.img
    

    However when I add an item to the list using this instead:

    storiesModel.insert(insertIndex, { elementType: "gridelement", topimg: topid, leftimg: leftid, rightimg: rightid })
    

    I don't have access to any of the properties. Funnily enough, if I add the element using "gridelement" as the elementType and "img: imgid" as one of the properties, I can still access img just fine, however topimg, leftimg and rightimg all give me the following error:
    qrc:/res/qml/learningstories/PhotoGrid.qml:26:28: Unable to assign [undefined] to QString

    At first I thought it may have been due to topid, leftid, or rightid playing up, but if I manually assign the delegate properties using topid, leftid and rightid it works completely fine.

    Is there a way I can print all of the properties of modelData so I can see what's actually being stored in there? Seems weird that it only stores select properties.

    P 1 Reply Last reply 8 Jul 2015, 10:23
    0
    • E eLim
      8 Jul 2015, 06:19

      Hi. I currently have a ListView with a ListModel that uses a Loader for the delegate.

      in the Loader I have the following:

      onLoaded: {
          item.modelData = model
      }
      

      Every Component that the delegate can use as its source has the modelData property.
      When I add the following item to the list using the insert command:

       storiesModel.insert(insertIndex, { elementType: "imageelement", img: imgid })
      

      I am able to access that "img" property from inside the delegate without any issue at all, using the following:

       imgId: modelData.img
      

      However when I add an item to the list using this instead:

      storiesModel.insert(insertIndex, { elementType: "gridelement", topimg: topid, leftimg: leftid, rightimg: rightid })
      

      I don't have access to any of the properties. Funnily enough, if I add the element using "gridelement" as the elementType and "img: imgid" as one of the properties, I can still access img just fine, however topimg, leftimg and rightimg all give me the following error:
      qrc:/res/qml/learningstories/PhotoGrid.qml:26:28: Unable to assign [undefined] to QString

      At first I thought it may have been due to topid, leftid, or rightid playing up, but if I manually assign the delegate properties using topid, leftid and rightid it works completely fine.

      Is there a way I can print all of the properties of modelData so I can see what's actually being stored in there? Seems weird that it only stores select properties.

      P Offline
      P Offline
      p3c0
      Moderators
      wrote on 8 Jul 2015, 10:23 last edited by
      #2

      @eLim Can you post some more code ?

      Is there a way I can print all of the properties of modelData so I can see what's actually being stored in there? Seems weird that it only stores select properties.

      Yes in this way:

      for(var prop in modelData) { // your property
          console.log("Property: ", prop, "Value: ", modelData[prop])
      }
      

      157

      E 1 Reply Last reply 12 Jul 2015, 17:14
      0
      • P p3c0
        8 Jul 2015, 10:23

        @eLim Can you post some more code ?

        Is there a way I can print all of the properties of modelData so I can see what's actually being stored in there? Seems weird that it only stores select properties.

        Yes in this way:

        for(var prop in modelData) { // your property
            console.log("Property: ", prop, "Value: ", modelData[prop])
        }
        
        E Offline
        E Offline
        eLim
        wrote on 12 Jul 2015, 17:14 last edited by eLim 7 Dec 2015, 17:20
        #3

        @p3c0 Hey thanks for that. It seems like my properties simply refuse to be passed into the modelData. Not really sure what's up.
        I'm currently using a Loader to load a specific Component into a ListView dependent on its "elementType"

        ListView {
            id: storiesCreatorList
            anchors.fill: parent
            visible: false
            clip: true
        
            model: storiesModel
            delegate:
                Loader {
                    sourceComponent: {
                        elementList.push(this)
        
                        if(elementType == coverElement)
                            return coverPhotoScreen
        
                        if(elementType == adderElement)
                            return addElement
        
                        if(elementType == textElement)
                            return textEditorElement
        
                        if(elementType == imageElement)
                            return photoElement
        
                        if(elementType == gridElement)
                            return photoGridElement
        
                        if(elementType == frameHeaderElement)
                            return frameworkHeaderElement
        
                        if(elementType == frameContentElement)
                            return frameworkContentElement
                    }
        
                    onLoaded: {
                        item.modelData = model
                    }
                }
        }
        

        One of the components looks like this:

        Component {
            id: frameworkHeaderElement
        
            Rectangle {
                property var modelData: []
        
                id: frameworkHeaderElementRect
                width: stories.width
                height: stories.height * 0.075
                color: "transparent"
        
                onModelDataChanged: {
                    for(var prop in modelData)
                        console.log("Property: ", prop, ", Value: ", modelData[prop])
                }
        
                Text {
                    id: frameworkHeaderText
                    anchors.left: parent.left
                    anchors.leftMargin: parent.width * 0.05
        
                    //text: modelData.headerText <-- undefined apparently
                    font.family: "Museo Sans"
                    font.pixelSize: parent.height * 0.75
                    color: "#f26259"
                }
            }
        }
        

        As you can see, the Component contains a "modelData" property for storing its information from the ListView's model. This is due to the various components having different custom properties. I add this component to the list using the following:

        storiesModel.append({ elementType: "frameheaderelement", headerText: header }) //Note header here is text from the function this is called in. It is just a regular QML string, it works fine
        

        In the component code I posted you can see that I'm printing all the modelData properties as you explained. This is what the console shows:

        qml: Property:  objectName , Value:  
        qml: Property:  index , Value:  2
        qml: Property:  model , Value:  QQmlDMAbstractItemModelData(0x38595bd8)
        qml: Property:  hasModelChildren , Value:  false
        qml: Property:  elementType , Value:  frameheaderelement
        qml: Property:  modelData , Value:  frameheaderelement
        qml: Property:  objectNameChanged , Value:  function() { [code] }
        qml: Property:  modelIndexChanged , Value:  function() { [code] }
        qml: Property:  __0 , Value:  function() { [code] }
        qml: Property:  __1 , Value:  function() { [code] }
        

        I can see "elementType" in there, but where did "headerText" go? This is really confusing me :(

        Edit: Why is there a "modelData" property in my modelData property? What's going on x_x

        P 1 Reply Last reply 13 Jul 2015, 03:16
        0
        • E eLim
          12 Jul 2015, 17:14

          @p3c0 Hey thanks for that. It seems like my properties simply refuse to be passed into the modelData. Not really sure what's up.
          I'm currently using a Loader to load a specific Component into a ListView dependent on its "elementType"

          ListView {
              id: storiesCreatorList
              anchors.fill: parent
              visible: false
              clip: true
          
              model: storiesModel
              delegate:
                  Loader {
                      sourceComponent: {
                          elementList.push(this)
          
                          if(elementType == coverElement)
                              return coverPhotoScreen
          
                          if(elementType == adderElement)
                              return addElement
          
                          if(elementType == textElement)
                              return textEditorElement
          
                          if(elementType == imageElement)
                              return photoElement
          
                          if(elementType == gridElement)
                              return photoGridElement
          
                          if(elementType == frameHeaderElement)
                              return frameworkHeaderElement
          
                          if(elementType == frameContentElement)
                              return frameworkContentElement
                      }
          
                      onLoaded: {
                          item.modelData = model
                      }
                  }
          }
          

          One of the components looks like this:

          Component {
              id: frameworkHeaderElement
          
              Rectangle {
                  property var modelData: []
          
                  id: frameworkHeaderElementRect
                  width: stories.width
                  height: stories.height * 0.075
                  color: "transparent"
          
                  onModelDataChanged: {
                      for(var prop in modelData)
                          console.log("Property: ", prop, ", Value: ", modelData[prop])
                  }
          
                  Text {
                      id: frameworkHeaderText
                      anchors.left: parent.left
                      anchors.leftMargin: parent.width * 0.05
          
                      //text: modelData.headerText <-- undefined apparently
                      font.family: "Museo Sans"
                      font.pixelSize: parent.height * 0.75
                      color: "#f26259"
                  }
              }
          }
          

          As you can see, the Component contains a "modelData" property for storing its information from the ListView's model. This is due to the various components having different custom properties. I add this component to the list using the following:

          storiesModel.append({ elementType: "frameheaderelement", headerText: header }) //Note header here is text from the function this is called in. It is just a regular QML string, it works fine
          

          In the component code I posted you can see that I'm printing all the modelData properties as you explained. This is what the console shows:

          qml: Property:  objectName , Value:  
          qml: Property:  index , Value:  2
          qml: Property:  model , Value:  QQmlDMAbstractItemModelData(0x38595bd8)
          qml: Property:  hasModelChildren , Value:  false
          qml: Property:  elementType , Value:  frameheaderelement
          qml: Property:  modelData , Value:  frameheaderelement
          qml: Property:  objectNameChanged , Value:  function() { [code] }
          qml: Property:  modelIndexChanged , Value:  function() { [code] }
          qml: Property:  __0 , Value:  function() { [code] }
          qml: Property:  __1 , Value:  function() { [code] }
          

          I can see "elementType" in there, but where did "headerText" go? This is really confusing me :(

          Edit: Why is there a "modelData" property in my modelData property? What's going on x_x

          P Offline
          P Offline
          p3c0
          Moderators
          wrote on 13 Jul 2015, 03:16 last edited by
          #4

          @eLim The only problem in the above code that I see is that if headerText is not set during append and the elementType if condition in sourceComponent as you have passed a string it should be a string in condition too.
          For reference here is a code similar to yours:

          import QtQuick 2.0
          
          Item {
              width: 100
              height: 100
          
              ListModel {
                  id: myModel
              }
          
              ListView {
                  id: listview
                  anchors.fill: parent
                  model: myModel
                  delegate: Loader {
                      sourceComponent: {
                          if(name == "abc")
                              return myComp1
                          if(name == "xyz")
                              return myComp2
                      }
                      onLoaded: item.modelData = model
                  }
              }
          
              Component {
                  id: myComp1
                  Text {
                      property var modelData: []
                      text: modelData.name + " " + modelData.age
                  }
              }
          
              Component {
                  id: myComp2
                  Text {
                      property var modelData: []
                      text: modelData.age + " " + modelData.name
                  }
              }
          
              Component.onCompleted: {
                  myModel.append({ name: "abc", age: 10 })
                  myModel.append({ name: "xyz", age: 12 })
              }
          }
          
          

          157

          1 Reply Last reply
          0
          • E Offline
            E Offline
            eLim
            wrote on 13 Jul 2015, 15:58 last edited by eLim
            #5

            I've managed to solve the problem by first adding a second property to the Components, so now the Component has this at the top:

             Component {
                id: frameworkHeaderElement
            
                Rectangle {
                    property var modelData: []
                    property var propData: []
                    ...
                }
                ...
             }
            

            Then when the Component is Loaded during the Loader I've changed the onLoaded function to the following:

            onLoaded: {
                item.modelData = model
                item.propData = storiesModel.get(index)
            }
            

            Now I can access my index using modelData, and I can access all of my properties (which may be unique to a Component) through propData as follows

            text: propData.headerText
            

            I'm sure there's a better way to solve this, but for the time being this works just fine for what I need.

            Thanks for your help!

            1 Reply Last reply
            0

            1/5

            8 Jul 2015, 06:19

            • 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