Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    Solved Is it possible to recreate the ListView.delegate model Property behavior in pure QML?

    QML and Qt Quick
    3
    12
    746
    Loading More Posts
    • 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.
    • L
      LowLevelM last edited by LowLevelM

      If im using the delegate property im able to overwrite the visual appearace of the list items
      inside of the delegate all the model.item properties are available + the index of the model-item

      im nearly able to reproduce the model forwarding but have no idea how i can also get the model.index property into my delegate, could it be that the ListView implementation is doing C++ magic here that i can't rebuild with pure QML?

      Sample-Source:

      i've got a simple example with a ListModel with an attribute name and myValue, a ListView showing the model and my own list view like implementation that try to show the same content, as you can see the index is undefined in my implementation, its clear to me that i have not introduced this property but i also have no idea how to extend model property with the index attribute

      I hope someone got an idea how to replicate (at best) the interface of ListView

      DelegateModelList.qml

      import QtQuick 2.5
      
      Item {
          id: root
      
          property alias model : repeater.model // needs to be an alias
          property Component delegate
      
          Column {
              Repeater {
                  id: repeater
                  Loader {
                      // introduces "model" into loaded delegate scope
                      // how to add index to model?
                      property var model: repeater.model.get(index)
                      sourceComponent: root.delegate
                  }
              }
          }
      }
      

      DelegateModelListTest.qml

      import QtQuick 2.5
      import QtQuick.Window 2.5
      
      Window {
          width: 600
          height: 600
      
          ListModel {
              id: testModel
              ListElement { name: "Item 1"; myValue: 10 }
              ListElement { name: "Item 2"; myValue: 20 }
              ListElement { name: "Item 3"; myValue: 30 }
              ListElement { name: "Item 4"; myValue: 40 }
              ListElement { name: "Item 5"; myValue: 50 }
          }
      
          Row {
              ListView {
                  id: listView
      
                  width: 300
                  height: 300
      
                  model: testModel
      
                  delegate: Rectangle {
                      width: parent.width
                      height: 30
                      border { width: 1 }
                      Text { text: model.name+"("+model.index+"), myValue: "+model.myValue }
                  }
              }
      
              DelegateModelList {
                  id: myList
      
                  width: 300
                  height: 300
      
                  model: testModel
      
                  delegate: Rectangle {
                      width: 300
                      height: 30
                      border { width: 1 }
                      Text { text: model.name+"("+model.index+"), myValue: "+model.myValue }
                  }
              }
          }
      }
      

      0_1563465056245_Screenshot from 2019-07-18 17-49-03.png

      Thanks for any help

      1 Reply Last reply Reply Quote 0
      • S
        shaan7 last edited by

        I was able to achieve it like this-

                Loader {
                        // introduces "model" into loaded delegate scope
                        // how to add index to model?
                        property var model: repeater.model.get(index)
                        sourceComponent: root.delegate
        
                        Binding {
                            target: model
                            property: "index"
                            value: index
                        }
                    }
        
        1 Reply Last reply Reply Quote 1
        • L
          LowLevelM last edited by

          Thanks for this ultra short solution

          1 Reply Last reply Reply Quote 0
          • GrecKo
            GrecKo Qt Champions 2018 last edited by

            Why don't you just do property alias delegate: repeater.delegate?
            You won't have to do anything then.
            Note that while having supbar performances, your solution currently only works with ListModel (or custom models providing a get function). It won't work with a generic QAbstractListModel, or a js array.
            I also believe your item won't be updated if some role data gets updated in the ListModel.

            Also you might want to remove the wrapping Item and just use the Column as the root item. It will have useful implicitWidth and implicitHeight properties.

            Can you tell us a bit more about what you are trying to achieve and why ListView or Column +Repeater don't fill your needs?

            L 1 Reply Last reply Reply Quote 1
            • L
              LowLevelM @GrecKo last edited by LowLevelM

              @GrecKo

              Why don't you just do property alias delegate: repeater.delegate?
              You won't have to do anything then.

              perfect - QML is still very magical to me, where does the model property come from when using the alias?

              DelegateModelList.qml

              import QtQuick 2.5
              
              Item {
                  id: root
              
                  property alias model : repeater.model // needs to be an alias
                  property alias delegate: repeater.delegate // prevents using loader
              
                  Column {
                      Repeater {
                          id: repeater
                      }
                  }
              }
              

              Also you might want to remove the wrapping Item and just use the Column as the root item

              Where to put my alias properties then?

              Can you tell us a bit more about what you are trying to achieve and why ListView or Column +Repeater don't fill your needs?

              i asked that in another post, i've already build a Flickable based version of the list which perfectly suits my animation needs, but still would use ListView if the animation behavior can be "fixed", i use this type of list in serveral places of my software so it should be delegateable etc. - but as i said i would be more then happy if ListView is capable enough, that also the reason why i try to replicate the ListView Interface a litte, just to be able to replace all the usages of ListView with my new list (without the need to change the model usage)

              https://forum.qt.io/topic/105085/can-t-get-my-listview-scrollbehavior-correct-in-my-simple-example

              L 1 Reply Last reply Reply Quote 0
              • L
                LowLevelM @LowLevelM last edited by LowLevelM

                But what is the solution if i want to add a spacing Rectangle to my repeated delegate
                can i still work with alias or is then the Loader needed? how is then the aliasing of the delegate/model property handled?

                this nearly(index binding does not work) works, but is not as nice as your example(with alias), but i can't get it working, still fighting with alias put through i think

                DelegateModelList.qml

                import QtQuick 2.5
                
                Item {
                    id: root
                
                    property alias model : repeater.model // needs to be an alias
                    property Component delegate // i would like to alias, but how?
                    property real spacing
                
                    Column {
                        Repeater {
                            id: repeater
                
                            Column {
                                Loader {
                                    property var model: repeater.model.get(index)
                                    sourceComponent: root.delegate
                
                                    // does not work anymore (and i think its as "working" but no good solution, the alias is much better)
                                    Binding {
                                        target: model
                                        property: "index"
                                        value: index
                                    }
                                }
                
                                // spacing
                                Rectangle { width: parent.width; height: root.spacing }
                            }
                
                        }
                    }
                }
                
                

                DelegateModelListTest.qml

                import QtQuick 2.5
                import QtQuick.Window 2.5
                
                Window {
                    width: 600
                    height: 600
                
                    ListModel {
                        id: testModel
                        ListElement { name: "Item 1"; myValue: 10 }
                        ListElement { name: "Item 2"; myValue: 20 }
                        ListElement { name: "Item 3"; myValue: 30 }
                        ListElement { name: "Item 4"; myValue: 40 }
                        ListElement { name: "Item 5"; myValue: 50 }
                    }
                
                    Row {
                        ListView {
                            id: listView
                
                            width: 300
                            height: 300
                
                            model: testModel
                
                            spacing: 11
                
                            delegate: Rectangle {
                                width: parent.width
                                height: 30
                                border { width: 1 }
                                Text { text: model.name+"("+model.index+"), myValue: "+model.myValue }
                            }
                        }
                
                        DelegateModelList {
                            id: myList
                
                            width: 300
                            height: 300
                
                            model: testModel
                
                            spacing: 11
                
                            delegate: Rectangle {
                                width: 300
                                height: 30
                                border { width: 1 }
                                Text { text: model.name+"("+model.index+"), myValue: "+model.myValue }
                            }
                        }
                    }
                }
                
                

                0_1563515708912_Screenshot from 2019-07-19 07-54-57.png

                i want to solve my animation problem AND want to understand how QML works inside

                1 Reply Last reply Reply Quote 0
                • GrecKo
                  GrecKo Qt Champions 2018 last edited by

                  If you made the Column the root item, you could put aliases there. Your Item is useless and even removes features from your Column.
                  Column also has a spacing property, so no need to add your own.

                  perfect - QML is still very magical to me, where does the model property come from when using the alias?

                  Those are set as context properties for each delegate when they are instantiated by the ListView

                  L 1 Reply Last reply Reply Quote 0
                  • L
                    LowLevelM @GrecKo last edited by LowLevelM

                    @GrecKo

                    Column also has a spacing property

                    a that works

                    DelegateModelList.qml

                    import QtQuick 2.5
                    
                    Column {
                        property alias model : repeater.model
                        property alias delegate : repeater.delegate
                    
                        Repeater {
                            id: repeater
                            delegate: item
                        }
                    }
                    
                    

                    but what if i still want to add for example a green rectangle to every item inside my DelegateModelList.qml, as long as i just alias everything around it seems to work - but when i try to add some other components i need to use the Loader and everything gets messy, how would you add (just for the sake of it) a rectangle spacing feature to this example without using the spacing of the column? the spacing should not be part of my delegate component, only in my list

                    1 Reply Last reply Reply Quote 0
                    • GrecKo
                      GrecKo Qt Champions 2018 last edited by GrecKo

                      You could do it like so:

                      import QtQuick 2.5
                      
                      Column {
                          id: root
                          property alias model : repeater.model
                          property Component delegate
                      
                          Repeater {
                              id: repeater
                              delegate: Column {
                                  id: column
                                  property var _model: model
                                  width: parent.width
                                  Rectangle {
                                      width: parent.width
                                      height: 10
                                      color: "lightblue"
                                  }
                                  Loader {
                                      property var model: column._model
                                      width: parent.width
                                      sourceComponent: root.delegate
                                  }
                              }
                          }
                      }
                      

                      What it does is that it explicitely set a model property (equals to the model context property of the delegate) in the Loader. Properties of a Loader are exposed as context properties in its loaded object.

                      L 1 Reply Last reply Reply Quote 1
                      • L
                        LowLevelM @GrecKo last edited by LowLevelM

                        @GrecKo
                        thanks alot, getting more into QML in 20minutes writing with you then 2 days of trial&error :)

                        also seen my current ListView question with the animation, any idea or is that really something that needs a special list?

                        1 Reply Last reply Reply Quote 0
                        • GrecKo
                          GrecKo Qt Champions 2018 last edited by

                          Your other question would require trial and error for me, I guess it can work but I don't know how.
                          Sorry, I can't really take the time to answer it.

                          L 1 Reply Last reply Reply Quote 0
                          • L
                            LowLevelM @GrecKo last edited by

                            @GrecKo

                            Sorry, I can't really take the time to answer it.

                            absolutely no problem - you already helped enough - thank you

                            1 Reply Last reply Reply Quote 0
                            • First post
                              Last post