Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. General talk
  3. Brainstorm
  4. passing lists of data to a Component
Forum Updated to NodeBB v4.3 + New Features

passing lists of data to a Component

Scheduled Pinned Locked Moved Solved Brainstorm
13 Posts 3 Posters 1.7k 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.
  • T Offline
    T Offline
    TomZ
    wrote on 17 Mar 2024, 21:00 last edited by
    #2

    Yap, that's a bit messy...

    You obviously know about the Loader.setSource second argument. Which doesn't work for a Component.

    Here is one solution:

    Loader {
      onLoaded: item.someProperty = someValue
    }
    

    Your component should have that property and your code here can set it to anything.
    Biggest downside is that the property is null for a small while which may cause you to have warnings unless you check for that in usages.

    Now, the main upside here is that you can call into C++ code and pass in a 'parent' object for memory management (QObject constructor arg). If you pass in the 'item' (property of loader) then your created QObject's livespan will be tied to the loaded item.

    I use this method often in things like a delegate. Your delegate is a thin wrapper around a Loader, the loader selects the Compenent on some properties in the 'modelData' and then assigns the modelData to some property of the component on load.

    M 1 Reply Last reply 18 Mar 2024, 16:04
    0
    • T TomZ
      17 Mar 2024, 21:00

      Yap, that's a bit messy...

      You obviously know about the Loader.setSource second argument. Which doesn't work for a Component.

      Here is one solution:

      Loader {
        onLoaded: item.someProperty = someValue
      }
      

      Your component should have that property and your code here can set it to anything.
      Biggest downside is that the property is null for a small while which may cause you to have warnings unless you check for that in usages.

      Now, the main upside here is that you can call into C++ code and pass in a 'parent' object for memory management (QObject constructor arg). If you pass in the 'item' (property of loader) then your created QObject's livespan will be tied to the loaded item.

      I use this method often in things like a delegate. Your delegate is a thin wrapper around a Loader, the loader selects the Compenent on some properties in the 'modelData' and then assigns the modelData to some property of the component on load.

      M Offline
      M Offline
      mzimmers
      wrote on 18 Mar 2024, 16:04 last edited by mzimmers
      #3

      @TomZ thanks for the reply. One of my goals here is to make the EquipmentConfigList.qml file reusable. I'm looking for a way to aggregate the data I need to display (I would expect to do this inside my Flickable or my reference to the EquipmentConfigList) so that I can use a Repeater (or something similar) to display all the information that's passed to EquipmentConfigList.qml. In C++ I'd use an array of structs (probably) but I don't know how to do this in QML. Any thoughts?

      EDIT:

      This is sort of pseudocode outline of what I'd like to do:

      EquipmentA.qml
      EquipmentB.qml
      EquipmentC.qml
      
      // EquipmentConfig.qml
      
      if (category is A) {
          list = makeListForCategoryA // choosing only the properties I want to display for A
          EquipmentConfigList(list)
      } else if (category is B) {
          list = makeListForCategoryB
          EquipmentConfigList(list)
      } // etc.
      

      My EquipmentA/B/C.qml files ideally wouldn't have to be QML, though I'm not sure what I'd replace them with. But the gist is to have a reusable list that I can conditionally populate based on the category of the equipment object.

      Thanks...

      T 1 Reply Last reply 18 Mar 2024, 22:26
      0
      • M mzimmers
        18 Mar 2024, 16:04

        @TomZ thanks for the reply. One of my goals here is to make the EquipmentConfigList.qml file reusable. I'm looking for a way to aggregate the data I need to display (I would expect to do this inside my Flickable or my reference to the EquipmentConfigList) so that I can use a Repeater (or something similar) to display all the information that's passed to EquipmentConfigList.qml. In C++ I'd use an array of structs (probably) but I don't know how to do this in QML. Any thoughts?

        EDIT:

        This is sort of pseudocode outline of what I'd like to do:

        EquipmentA.qml
        EquipmentB.qml
        EquipmentC.qml
        
        // EquipmentConfig.qml
        
        if (category is A) {
            list = makeListForCategoryA // choosing only the properties I want to display for A
            EquipmentConfigList(list)
        } else if (category is B) {
            list = makeListForCategoryB
            EquipmentConfigList(list)
        } // etc.
        

        My EquipmentA/B/C.qml files ideally wouldn't have to be QML, though I'm not sure what I'd replace them with. But the gist is to have a reusable list that I can conditionally populate based on the category of the equipment object.

        Thanks...

        T Offline
        T Offline
        TomZ
        wrote on 18 Mar 2024, 22:26 last edited by
        #4

        @mzimmers I think you are on the right track, but you seem to be stuck on some minor issues.

        First, remember the strong seperation of model/view. In this specific case you can easily have one model that feeds all 3 types of views. You KNOW that a view will only ask for certain properties if the data is a certain type, as such you can optimize your model code to match (add asserts, even).

        So, in short, to feed your 3 types of views you should only have one backing model. It simply has different properties you query for a specific view.

        Second,
        you can use a Loader with a construction like:

        ListView {
           model: someModel
           Loader {
             source: {
               if (model.someProperty)
                 return "./Page1.qml";
              if (model.foo)
                 return "./Page2.qml";
              return "./Page3.qml";
           }
        }
        

        Then your pages simply need to use the model property to fetch the data they want to use.

        Page1.qml
        
        Label {
           text: model.something
        }
        
        M 1 Reply Last reply 18 Mar 2024, 23:27
        2
        • T TomZ
          18 Mar 2024, 22:26

          @mzimmers I think you are on the right track, but you seem to be stuck on some minor issues.

          First, remember the strong seperation of model/view. In this specific case you can easily have one model that feeds all 3 types of views. You KNOW that a view will only ask for certain properties if the data is a certain type, as such you can optimize your model code to match (add asserts, even).

          So, in short, to feed your 3 types of views you should only have one backing model. It simply has different properties you query for a specific view.

          Second,
          you can use a Loader with a construction like:

          ListView {
             model: someModel
             Loader {
               source: {
                 if (model.someProperty)
                   return "./Page1.qml";
                if (model.foo)
                   return "./Page2.qml";
                return "./Page3.qml";
             }
          }
          

          Then your pages simply need to use the model property to fetch the data they want to use.

          Page1.qml
          
          Label {
             text: model.something
          }
          
          M Offline
          M Offline
          mzimmers
          wrote on 18 Mar 2024, 23:27 last edited by mzimmers
          #5

          @TomZ I think this is moving in the right direction. A couple points:

          I am indeed maintaining a single model. It contains a list of all the equipment items in the system.

          There will be multiple equipment items of the same category in a system. For this reason, I need to somehow inform my Page1/2/3.qml files of the equipment object I'm using. By the time I'm in this QML area, I've already accessed the model and have a single instance of Equipment in my QML.

          Also (minor) when I changed my Flickable to a ListView, it no longer flicks. Here's the complete code for the section:

          // Flickable {
          ListView {
              boundsBehavior: Flickable.StopAtBounds
              clip: true
              contentHeight: contentItem.childrenRect.height
              implicitWidth: parent.width
              implicitHeight: innerPane.availableHeight
              EquipmentConfigList { // this would become Page1/2/3.qml
                  id: equipmentConfigList
                  Layout.fillHeight: true
                  Layout.preferredWidth: rightColumn.availableWidth
                  equipment: equipmentCopy
              }
          }
          

          Any idea why it doesn't flick for me anymore?

          Thanks for the help...

          G 1 Reply Last reply 19 Mar 2024, 00:46
          0
          • M mzimmers
            18 Mar 2024, 23:27

            @TomZ I think this is moving in the right direction. A couple points:

            I am indeed maintaining a single model. It contains a list of all the equipment items in the system.

            There will be multiple equipment items of the same category in a system. For this reason, I need to somehow inform my Page1/2/3.qml files of the equipment object I'm using. By the time I'm in this QML area, I've already accessed the model and have a single instance of Equipment in my QML.

            Also (minor) when I changed my Flickable to a ListView, it no longer flicks. Here's the complete code for the section:

            // Flickable {
            ListView {
                boundsBehavior: Flickable.StopAtBounds
                clip: true
                contentHeight: contentItem.childrenRect.height
                implicitWidth: parent.width
                implicitHeight: innerPane.availableHeight
                EquipmentConfigList { // this would become Page1/2/3.qml
                    id: equipmentConfigList
                    Layout.fillHeight: true
                    Layout.preferredWidth: rightColumn.availableWidth
                    equipment: equipmentCopy
                }
            }
            

            Any idea why it doesn't flick for me anymore?

            Thanks for the help...

            G Offline
            G Offline
            GrecKo
            Qt Champions 2018
            wrote on 19 Mar 2024, 00:46 last edited by
            #6

            If you want to have different delegate components based on a type role, use DelegateChooser instead of Loader for delegates.

            If you want to have a single generic delegate, you could define all the possible fields and conditionally show them if there is a corresponding property. Or fetch the properties from the meta-object. Do you want to do that though? What if you want to display a gauge/slider? How would you define the min/max value?

            M 1 Reply Last reply 19 Mar 2024, 01:45
            2
            • G GrecKo
              19 Mar 2024, 00:46

              If you want to have different delegate components based on a type role, use DelegateChooser instead of Loader for delegates.

              If you want to have a single generic delegate, you could define all the possible fields and conditionally show them if there is a corresponding property. Or fetch the properties from the meta-object. Do you want to do that though? What if you want to display a gauge/slider? How would you define the min/max value?

              M Offline
              M Offline
              mzimmers
              wrote on 19 Mar 2024, 01:45 last edited by
              #7

              @GrecKo said in passing lists of data to a Component:

              What if you want to display a gauge/slider? How would you define the min/max value?

              You're a mind reader - I will indeed need to do that elsewhere (the customer wants separate pages for viewing and editing the Equipment fields). I was starting with the easy (readonly) stuff.

              I'm still having trouble putting this all together, though. I need a Flickable (or ListView) that will conditionally display properties of the Equipment object based on the category of the equipment.

              Here's the basis of the Equipment class:

              enum EquipmentCategory {
                  CATEGORY_UNKNOWN,
                  CATEGORY_VSP,
                  CATEGORY_HEATER,
                  CATEGORY_HEATPUMP,
                  // ...
              }
              class Equipment : public QObject
              {
                  Q_OBJECT
                  QML_ELEMENT
              
                  EquipmentCategory m_category = CATEGORY_UNKNOWN; // exposed to QML
                  // ...
              }
              

              So, how do I use a DelegateChooser here:

              Flickable {
                  // what is my model?
                  DelagateChooser {
                      role: category
                      DelegateChoice {
                          role: CATEGORY_VSP // this doesn't seem right
                          VspDelegate {} // contained an another file
                      }
                      DelegateChoice {
                          role: CATEGORY_HEATER
                          HeaterDelegate {} // contained an another file
                      }
                  }
              }
              

              Is this on the right track?

              Thanks...

              G 1 Reply Last reply 19 Mar 2024, 15:14
              0
              • M mzimmers
                19 Mar 2024, 01:45

                @GrecKo said in passing lists of data to a Component:

                What if you want to display a gauge/slider? How would you define the min/max value?

                You're a mind reader - I will indeed need to do that elsewhere (the customer wants separate pages for viewing and editing the Equipment fields). I was starting with the easy (readonly) stuff.

                I'm still having trouble putting this all together, though. I need a Flickable (or ListView) that will conditionally display properties of the Equipment object based on the category of the equipment.

                Here's the basis of the Equipment class:

                enum EquipmentCategory {
                    CATEGORY_UNKNOWN,
                    CATEGORY_VSP,
                    CATEGORY_HEATER,
                    CATEGORY_HEATPUMP,
                    // ...
                }
                class Equipment : public QObject
                {
                    Q_OBJECT
                    QML_ELEMENT
                
                    EquipmentCategory m_category = CATEGORY_UNKNOWN; // exposed to QML
                    // ...
                }
                

                So, how do I use a DelegateChooser here:

                Flickable {
                    // what is my model?
                    DelagateChooser {
                        role: category
                        DelegateChoice {
                            role: CATEGORY_VSP // this doesn't seem right
                            VspDelegate {} // contained an another file
                        }
                        DelegateChoice {
                            role: CATEGORY_HEATER
                            HeaterDelegate {} // contained an another file
                        }
                    }
                }
                

                Is this on the right track?

                Thanks...

                G Offline
                G Offline
                GrecKo
                Qt Champions 2018
                wrote on 19 Mar 2024, 15:14 last edited by
                #8

                @mzimmers said in passing lists of data to a Component:

                role: CATEGORY_VSP // this doesn't seem right

                use roleValue here. And properly expose your enum type to QML.

                The role property of DelegateChooser is a string, so specify the role name as a string here.

                M 2 Replies Last reply 19 Mar 2024, 23:02
                1
                • G GrecKo
                  19 Mar 2024, 15:14

                  @mzimmers said in passing lists of data to a Component:

                  role: CATEGORY_VSP // this doesn't seem right

                  use roleValue here. And properly expose your enum type to QML.

                  The role property of DelegateChooser is a string, so specify the role name as a string here.

                  M Offline
                  M Offline
                  mzimmers
                  wrote on 19 Mar 2024, 23:02 last edited by
                  #9
                  This post is deleted!
                  1 Reply Last reply
                  0
                  • G GrecKo
                    19 Mar 2024, 15:14

                    @mzimmers said in passing lists of data to a Component:

                    role: CATEGORY_VSP // this doesn't seem right

                    use roleValue here. And properly expose your enum type to QML.

                    The role property of DelegateChooser is a string, so specify the role name as a string here.

                    M Offline
                    M Offline
                    mzimmers
                    wrote on 19 Mar 2024, 23:28 last edited by
                    #10

                    @GrecKo so, this is what I have now (and it seems to work):

                    ListView {
                        anchors.fill: parent
                        model: equipmentCopy
                        clip: true
                        boundsBehavior: Flickable.StopAtBounds
                        delegate: DelegateChooser {
                            role: "category"
                            DelegateChoice {
                                roleValue: NgaUI.CATEGORY_VSP
                                delegate: EquipmentConfigList {
                                    equipment: equipmentCopy
                                }
                            }
                        }
                    }
                    

                    It's a little foreign to me, as I've never used an object as a model, but everything seems to work. Thanks for all the help on this.

                    1 Reply Last reply
                    0
                    • M Offline
                      M Offline
                      mzimmers
                      wrote on 20 Mar 2024, 13:28 last edited by
                      #11

                      @GrecKo Before I close this topic, I do have a couple of follow-up questions:

                      1. I don't seem to be using a list in the "classical" sense, in that I'm only displaying one item. I realize that a delegate (and therefore, a DelegateChooser) needs a list, but...is there a preferred way to implement what I'm doing? Without a list?

                      2. (sort of related) is it OK to use an object as the model for a ListView? It seems to work OK, but there's nothing in the docs that explicitly says I can do this, so I want to make sure this is licit.

                      Thanks...

                      G 1 Reply Last reply 22 Mar 2024, 14:06
                      0
                      • M mzimmers
                        20 Mar 2024, 13:28

                        @GrecKo Before I close this topic, I do have a couple of follow-up questions:

                        1. I don't seem to be using a list in the "classical" sense, in that I'm only displaying one item. I realize that a delegate (and therefore, a DelegateChooser) needs a list, but...is there a preferred way to implement what I'm doing? Without a list?

                        2. (sort of related) is it OK to use an object as the model for a ListView? It seems to work OK, but there's nothing in the docs that explicitly says I can do this, so I want to make sure this is licit.

                        Thanks...

                        G Offline
                        G Offline
                        GrecKo
                        Qt Champions 2018
                        wrote on 22 Mar 2024, 14:06 last edited by
                        #12

                        @mzimmers I didn't realize you didn't want to use this is a model/view but yes it is indeed supported to have a single object as a model. You were 1 link away ;) https://doc.qt.io/qt-6/qtquick-modelviewsdata-modelview.html#object-instances-as-models

                        using Loader like mentioned by TomZ is an alternative.

                        M 1 Reply Last reply 22 Mar 2024, 14:42
                        3
                        • G GrecKo
                          22 Mar 2024, 14:06

                          @mzimmers I didn't realize you didn't want to use this is a model/view but yes it is indeed supported to have a single object as a model. You were 1 link away ;) https://doc.qt.io/qt-6/qtquick-modelviewsdata-modelview.html#object-instances-as-models

                          using Loader like mentioned by TomZ is an alternative.

                          M Offline
                          M Offline
                          mzimmers
                          wrote on 22 Mar 2024, 14:42 last edited by
                          #13

                          @GrecKo yeah, this is a weird use case. I actually do want a list, just not a list in the Qt model/view/delegate sense. Ideally, I'd like to create a list (array/vector/whatever) of the properties I want to display, and pass it into a universal component for display, but creating and using that structure seems to be a bit out of reach for JS/QML/me. It's OK; this approach is working, if a bit inelegant.

                          1 Reply Last reply
                          0
                          • M mzimmers has marked this topic as solved on 3 Apr 2024, 17:03

                          11/13

                          20 Mar 2024, 13:28

                          • Login

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