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. accessing elements of a ListModel

accessing elements of a ListModel

Scheduled Pinned Locked Moved Solved QML and Qt Quick
27 Posts 3 Posters 8.0k Views 2 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.
  • mzimmersM mzimmers

    @Diracsbracket I'm sure that is a good option. My problem isn't how to populate the model; it's how to extract information from individual elements from within a loop.

    DiracsbracketD Offline
    DiracsbracketD Offline
    Diracsbracket
    wrote on last edited by
    #8

    @mzimmers said in accessing elements of a ListModel:

    My problem isn't how to populate the model;

    I'm afraid I don't get it indeed. As far as I understand it, your problem is exactly how to populate (in this case, modify) the model. As @fcarney said, the way to go is to update the model itself.
    And you can access elements of the model using the get() method of the model.

    mzimmersM 1 Reply Last reply
    1
    • DiracsbracketD Diracsbracket

      @mzimmers said in accessing elements of a ListModel:

      My problem isn't how to populate the model;

      I'm afraid I don't get it indeed. As far as I understand it, your problem is exactly how to populate (in this case, modify) the model. As @fcarney said, the way to go is to update the model itself.
      And you can access elements of the model using the get() method of the model.

      mzimmersM Offline
      mzimmersM Offline
      mzimmers
      wrote on last edited by
      #9

      @Diracsbracket thank you for that -- I actually discovered the get() function just after my previous post (doh).

      So...that's how I extract or modify the data in the ListModel. Now...how do I get that data to display? Currently, unless I update the repeater (which fcarney said I shouldn't do), I don't seem to pick up the text in the model.

      Thanks again...

      DiracsbracketD 1 Reply Last reply
      0
      • mzimmersM mzimmers

        @Diracsbracket thank you for that -- I actually discovered the get() function just after my previous post (doh).

        So...that's how I extract or modify the data in the ListModel. Now...how do I get that data to display? Currently, unless I update the repeater (which fcarney said I shouldn't do), I don't seem to pick up the text in the model.

        Thanks again...

        DiracsbracketD Offline
        DiracsbracketD Offline
        Diracsbracket
        wrote on last edited by
        #10

        @mzimmers
        If the model data is updated, the repeater delegates should automatically refresh as well, assuming that you nowhere have broken the bindings.

        import QtQuick 2.15
        import QtQuick.Controls 2.15
        import QtQuick.Window 2.15
        
        Window {
            width: 640
            height: 480
            title: 'UmTreeView'
            visible: true
        
            ListModel {
                id: lmodel
                ListElement{
                    txt: "text1"
                }
                ListElement{
                    txt: "text2"
                }
            }
        
            Column {
                Repeater {
                    model: lmodel
        
                    delegate: Text {
                        text: txt
                    }
                }
            }
        
            Button {
                y: 100
                text: "Button"
                onClicked: {
                    for (var i=0; i<lmodel.count;++i)
                    {
                        lmodel.get(i).txt = "Hello"
                    }
                }
            }
        }
        
        mzimmersM 1 Reply Last reply
        1
        • DiracsbracketD Diracsbracket

          @mzimmers
          If the model data is updated, the repeater delegates should automatically refresh as well, assuming that you nowhere have broken the bindings.

          import QtQuick 2.15
          import QtQuick.Controls 2.15
          import QtQuick.Window 2.15
          
          Window {
              width: 640
              height: 480
              title: 'UmTreeView'
              visible: true
          
              ListModel {
                  id: lmodel
                  ListElement{
                      txt: "text1"
                  }
                  ListElement{
                      txt: "text2"
                  }
              }
          
              Column {
                  Repeater {
                      model: lmodel
          
                      delegate: Text {
                          text: txt
                      }
                  }
              }
          
              Button {
                  y: 100
                  text: "Button"
                  onClicked: {
                      for (var i=0; i<lmodel.count;++i)
                      {
                          lmodel.get(i).txt = "Hello"
                      }
                  }
              }
          }
          
          mzimmersM Offline
          mzimmersM Offline
          mzimmers
          wrote on last edited by
          #11

          @Diracsbracket OK, I follow that (I think). Your example gave me the idea to do this:

          ListModel {
          id: bottleModel_19
          
            ListElement {
              // position 1
          	bottleLabel: "ETH"
            }
            ...
            
          Column {
            id: bottles
            Repeater {
              id: bottleRepeater
              model: (nbrBottlesInRack === 16) ? bottleModel_16 : bottleModel_19
              Bottle {
                cellText: model.bottleLabel
          

          It seems to work OK...does it look all right to you?

          1 Reply Last reply
          0
          • fcarneyF Offline
            fcarneyF Offline
            fcarney
            wrote on last edited by
            #12

            @mzimmers said in accessing elements of a ListModel:

            cellText: model.bottleLabel

            The properties of the ListElement should be accessible as just their names:

            cellText: bottleLabel
            

            The names of the properties should be showing up as accessible properties within the delegate Bottle.

            C++ is a perfectly valid school of magic.

            mzimmersM 1 Reply Last reply
            0
            • fcarneyF fcarney

              @mzimmers said in accessing elements of a ListModel:

              cellText: model.bottleLabel

              The properties of the ListElement should be accessible as just their names:

              cellText: bottleLabel
              

              The names of the properties should be showing up as accessible properties within the delegate Bottle.

              mzimmersM Offline
              mzimmersM Offline
              mzimmers
              wrote on last edited by mzimmers
              #13

              @fcarney that worked for the bottleLable property, but not the others. Perhaps because the other properties' names are the same as properties local to Bottle, and the interpreter gets confused?

              On the subject of eliminating my use of itemAt() in the repeater: how do you propose I re-implement this?

              function updateBottles() {
                ...
                for (i = 0; i < listSize; ++i) {
                  bottle = reagentManager.bottleList[i]
                  if (bottle === undefined) {
                    bottleRepeater.itemAt(i).cellColor = Theme.neutralLight
                  } else {
                    bottleRepeater.itemAt(i).cellColor = Theme.dark
                  }
                  ...
              

              This function is called whenever the view becomes visible, to update the bottle data from a C++ Q_PROPERTY.

              EDIT:

              I've replaced this functionality as follows:

                Column {
                Repeater {
                  Bottle {
                  cellColor: rack.getColor(index)
              
              function getColor(i) {
                var l_color
                var volume
                var minVolume
                var amountNeeded
                var bottle
              
                bottle = reagentManager.bottleList[i]
                if (bottle === undefined) {
                  l_color = Theme.neutralLight
                } else {
                  volume = bottle.volume
                  minVolume = bottle.minVolume
                  amountNeeded = bottle.amountNeeded
                  l_color = ((volume - minVolume) >= amountNeeded) ? "green" : "red"
                }
                return l_color
              }
              

              This eliminates the write to the repeater that fcarney said is a bad idea, but I get the impression I'm still not really doing this right and/or making unnecessary work for myself. Thoughts?

              Thanks...

              EDIT 2:

              So, I changed my Bottle delegate (is that the correct term?) to look like this:

                      Bottle {
                        cellX: model.x
                        cellY: model.y
                        cellHeight: model.height
                        cellWidth: model.width
                        cellText: (reagentManager.bottleList[index] !== undefined)
                                  ? reagentManager.bottleList[index].name
                                  : bottleLabel
                        cellColor: rack.getColor(index)
                        bottleScaleFactor: scaleFactor
                      }
              

              I believe that I can now do away with the updateBottles() function completely. How does this look to the experienced people here?

              1 Reply Last reply
              0
              • fcarneyF Offline
                fcarneyF Offline
                fcarney
                wrote on last edited by
                #14

                @mzimmers said in accessing elements of a ListModel:

                if (bottle === undefined) {
                bottleRepeater.itemAt(i).cellColor = Theme.neutralLight
                } else {
                bottleRepeater.itemAt(i).cellColor = Theme.dark
                }

                Bottle {
                  cellColor: reagentManager.bottleList[index] === undefined ? Theme.neutralLight : Theme.dark
                }
                

                Assuming a 1:1 relationship to repeater and bottleList.
                All properties in Bottle should be set from information flowing into it in a declarative manner.
                QML is a declarative language. Writing functions to set things is sometimes unavoidable, but should be minimized.

                C++ is a perfectly valid school of magic.

                mzimmersM 1 Reply Last reply
                0
                • fcarneyF fcarney

                  @mzimmers said in accessing elements of a ListModel:

                  if (bottle === undefined) {
                  bottleRepeater.itemAt(i).cellColor = Theme.neutralLight
                  } else {
                  bottleRepeater.itemAt(i).cellColor = Theme.dark
                  }

                  Bottle {
                    cellColor: reagentManager.bottleList[index] === undefined ? Theme.neutralLight : Theme.dark
                  }
                  

                  Assuming a 1:1 relationship to repeater and bottleList.
                  All properties in Bottle should be set from information flowing into it in a declarative manner.
                  QML is a declarative language. Writing functions to set things is sometimes unavoidable, but should be minimized.

                  mzimmersM Offline
                  mzimmersM Offline
                  mzimmers
                  wrote on last edited by
                  #15

                  @fcarney noted. The logic is actually a little more complicated than I showed in my example. Here's the real function:

                  function getColor(i) {
                          var l_color
                          var volume
                          var minVolume
                          var amountNeeded
                          var bottle
                  
                          bottle = reagentManager.bottleList[i]
                          if (bottle === undefined) {
                              l_color = Theme.neutralLight
                          } else {
                              volume = bottle.volume
                              minVolume = bottle.minVolume
                              amountNeeded = bottle.amountNeeded
                              l_color = ((volume - minVolume) >= amountNeeded) ? "green" : "red"
                          }
                          return l_color
                  

                  I'd be happy to do away with this if it didn't make the QML too wordy...

                  1 Reply Last reply
                  0
                  • fcarneyF Offline
                    fcarneyF Offline
                    fcarney
                    wrote on last edited by
                    #16

                    Are you taking data from 2 sources? If so you can build up a ListModel and combine multiple sources of data using a function. Then use that model as the model for your repeater.

                    The set function of ListModel takes a js object as input. Any time the lists change you can rebuild that list which will automatically update all the Bottles in the repeater.

                    C++ is a perfectly valid school of magic.

                    mzimmersM 1 Reply Last reply
                    0
                    • fcarneyF fcarney

                      Are you taking data from 2 sources? If so you can build up a ListModel and combine multiple sources of data using a function. Then use that model as the model for your repeater.

                      The set function of ListModel takes a js object as input. Any time the lists change you can rebuild that list which will automatically update all the Bottles in the repeater.

                      mzimmersM Offline
                      mzimmersM Offline
                      mzimmers
                      wrote on last edited by
                      #17

                      @fcarney said in accessing elements of a ListModel:

                      Are you taking data from 2 sources?

                      Yes I am: I have the positions and dimensions in a QML ListModel. The "real" information about the bottle (size, contents, expiration date, etc) comes from a view model.

                      If so you can build up a ListModel and combine multiple sources of data using a function. Then use that model as the model for your repeater.

                      I like the sound of this. How do I put this in a loop, so I don't have to do something like this?

                        ListModel {
                          id: bottleModel_19
                      
                          ListElement {
                            // position 1
                            x: 407
                            y: 18
                            height: 78
                            width: 78
                            bottleLabel: (reagentManager.bottleList[index] !== undefined)
                                         ? reagentManager.bottleList[index].name
                                         : "ETH"
                          }
                          ...
                      
                      1 Reply Last reply
                      0
                      • fcarneyF Offline
                        fcarneyF Offline
                        fcarney
                        wrote on last edited by fcarney
                        #18

                        No, use the methods for ListModel like insert.

                        onChangeOfSourceList: {
                          bottleModel_19.clear()
                          for(var count=0; count<x; ++count){ 
                            // insert, get, and set use js objects
                            bottleModel_19.insert(count, {
                              "x":list1[count].whatever,
                              ...  // repeat for items from both lists
                            })
                          }
                        }
                        

                        Edit: Maybe append is better. Also clear list each time you recreate the list.

                        C++ is a perfectly valid school of magic.

                        1 Reply Last reply
                        1
                        • mzimmersM Offline
                          mzimmersM Offline
                          mzimmers
                          wrote on last edited by
                          #19

                          Does onChangeOfSourceList correspond to the signal I emit when I've updated the list? Here's my property:

                            Q_PROPERTY(Bottles bottleList
                                           MEMBER m_bottleList
                                               NOTIFY bottleListChanged)
                          

                          I tried onbottleListChanged, but this isn't correct.

                          1 Reply Last reply
                          0
                          • fcarneyF Offline
                            fcarneyF Offline
                            fcarney
                            wrote on last edited by
                            #20

                            Yes, something that emits a signal that you are calling when you update lists.
                            It will be:

                            onBottleListChanged
                            

                            Notice the B gets capitalized. Is there another signal that can trigger this too? Then you will need to create a function that gets called in each instance.

                            function updateListModel(){
                              ...
                            }
                            onBottleListChanged: updateListModel()
                            onOtherListChanged: updateListModel()
                            

                            C++ is a perfectly valid school of magic.

                            mzimmersM 1 Reply Last reply
                            0
                            • fcarneyF fcarney

                              Yes, something that emits a signal that you are calling when you update lists.
                              It will be:

                              onBottleListChanged
                              

                              Notice the B gets capitalized. Is there another signal that can trigger this too? Then you will need to create a function that gets called in each instance.

                              function updateListModel(){
                                ...
                              }
                              onBottleListChanged: updateListModel()
                              onOtherListChanged: updateListModel()
                              
                              mzimmersM Offline
                              mzimmersM Offline
                              mzimmers
                              wrote on last edited by
                              #21

                              @fcarney to which component is the onBottleListChanged: applied? I've tried putting this in several places in my QML file, and the editor warns of an invalid property name. Am I supposed to put this in a Connections object?

                              I don't have another signal for a bottle list update. Earlier you asked:

                              Are you taking data from 2 sources?

                              Yes I am. I put some data in the QML ListModels. This is data pertaining to the UI itself (screen location of the representation, size, etc.) "Real" data about the bottles (label, contents, fill level) is kept in a C++ object. This seemed like a natural breakdown for the data; is using two sources a bad idea?

                              Thanks...

                              1 Reply Last reply
                              0
                              • fcarneyF Offline
                                fcarneyF Offline
                                fcarney
                                wrote on last edited by
                                #22

                                @mzimmers said in accessing elements of a ListModel:

                                Q_PROPERTY(Bottles bottleList
                                MEMBER m_bottleList
                                NOTIFY bottleListChanged)

                                What object has this in it?

                                C++ is a perfectly valid school of magic.

                                mzimmersM 1 Reply Last reply
                                0
                                • fcarneyF fcarney

                                  @mzimmers said in accessing elements of a ListModel:

                                  Q_PROPERTY(Bottles bottleList
                                  MEMBER m_bottleList
                                  NOTIFY bottleListChanged)

                                  What object has this in it?

                                  mzimmersM Offline
                                  mzimmersM Offline
                                  mzimmers
                                  wrote on last edited by
                                  #23

                                  @fcarney

                                  class ReagentManager : public QObject {
                                    Q_OBJECT
                                   public:
                                    Q_PROPERTY(Bottles bottleList
                                                   MEMBER m_bottleList
                                                       NOTIFY bottleListChanged)
                                  ...
                                  class ChangeConsumables : public QObject {
                                    Q_OBJECT
                                    ReagentManager m_reagentManager;
                                  ...
                                  }
                                  engine->rootContext()->setContextProperty("reagentManager", &m_reagentManager);
                                  
                                  1 Reply Last reply
                                  0
                                  • fcarneyF Offline
                                    fcarneyF Offline
                                    fcarney
                                    wrote on last edited by
                                    #24

                                    @mzimmers said in accessing elements of a ListModel:

                                    engine->rootContext()->setContextProperty("reagentManager", &m_reagentManager);

                                    Then its a connection on the reagentManager.

                                    C++ is a perfectly valid school of magic.

                                    mzimmersM 1 Reply Last reply
                                    0
                                    • fcarneyF fcarney

                                      @mzimmers said in accessing elements of a ListModel:

                                      engine->rootContext()->setContextProperty("reagentManager", &m_reagentManager);

                                      Then its a connection on the reagentManager.

                                      mzimmersM Offline
                                      mzimmersM Offline
                                      mzimmers
                                      wrote on last edited by
                                      #25

                                      @fcarney the reagentManager generates the signal, but who consumes it?

                                      fcarneyF 1 Reply Last reply
                                      0
                                      • mzimmersM mzimmers

                                        @fcarney the reagentManager generates the signal, but who consumes it?

                                        fcarneyF Offline
                                        fcarneyF Offline
                                        fcarney
                                        wrote on last edited by
                                        #26

                                        onBottleListChanged: updateListModel()

                                        You call the function that rebuilds your ListModel. Don't you want that to update when it changes? Also, you said you had two lists of data. Does it have a signal too?

                                        C++ is a perfectly valid school of magic.

                                        mzimmersM 1 Reply Last reply
                                        0
                                        • fcarneyF fcarney

                                          onBottleListChanged: updateListModel()

                                          You call the function that rebuilds your ListModel. Don't you want that to update when it changes? Also, you said you had two lists of data. Does it have a signal too?

                                          mzimmersM Offline
                                          mzimmersM Offline
                                          mzimmers
                                          wrote on last edited by
                                          #27

                                          @fcarney said in accessing elements of a ListModel:

                                          onBottleListChanged: updateListModel()

                                          Oh, OK...I see my problem now. I was trying to use this line of code from within the repeater. I see now that it should go in the containing Rectangle.

                                          You call the function that rebuilds your ListModel. Don't you want that to update when it changes? Also, you said you had two lists of data. Does it have a signal too?

                                          I have two sources of data: one in C++ and one in a QML ListModel. I actually have 2 QML ListModels, but only use one (which one to use is determined at runtime by an environment variable). The only signal is emitted by the C++ update function; nothing in the ListModels.

                                          As it turns out, I've been able to eliminate the use of the QML update function entirely (though I still need the getColor routine() above, so I won't need to use this feature here, but this has been very educational. Thank you for all the help.

                                          1 Reply Last reply
                                          1

                                          • Login

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