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. updating elements in a repeater?
Forum Updated to NodeBB v4.3 + New Features

updating elements in a repeater?

Scheduled Pinned Locked Moved Solved QML and Qt Quick
43 Posts 5 Posters 13.4k Views 4 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

    From the same QML file:

      ListModel {
        id: bottleModel
    
        ListElement {
          // position 1
          x: 400
          y: 17
          height: 75
          width: 75
        }
        ...
    
    kshegunovK Offline
    kshegunovK Offline
    kshegunov
    Moderators
    wrote on last edited by
    #27

    This is confusing, I thought the data is supposed to come from C++.

    Read and abide by the Qt Code of Conduct

    mzimmersM 1 Reply Last reply
    0
    • kshegunovK kshegunov

      This is confusing, I thought the data is supposed to come from C++.

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

      I know, I'm doing a lousy job of explaining this. in C++:

      typedef QVector<Bottle> Bottles;
      class ReagentManager : public QObject {
        Q_OBJECT
       private:
        Bottles m_bottleList;
      }
      <in another file>
        ReagentManager m_reagentManager;
        engine->rootContext()->setContextProperty("reagentManager", &m_reagentManager);
      

      In QML:

          onVisibleChanged: {
            if (visible) {
              reagentManager.updateBottleList()
              rack.updateBottles()
            }
          }
      
          // update our QML array based on the C++ model.
          function updateBottles() {
            var modelSize = bottleModel.count
            var i
            var l_color
            var volume
            var minVolume
            var amountNeeded
            var name
      
            for (i = 0; i < modelSize; ++i) {
              name = reagentManager.getName(i)
              bottleRepeater.itemAt(i).cellText = name
      
              volume = reagentManager.m_volume
              minVolume = reagentManager.getMinVolume(i)
              amountNeeded = reagentManager.getAmountNeeded(i)
              l_color = ((volume - minVolume) >= amountNeeded) ? "green" : "red"
              bottleRepeater.itemAt(i).cellColor = l_color
            }
          }
      

      So, my QML function calls C++ routines to obtain the needed data. I'm trying to convert this to the approach you suggested; this is where I ran into the problem with the struct.

      I still don't see where the QVariantList comes into play, though.

      kshegunovK ODБOïO 2 Replies Last reply
      0
      • mzimmersM mzimmers

        I know, I'm doing a lousy job of explaining this. in C++:

        typedef QVector<Bottle> Bottles;
        class ReagentManager : public QObject {
          Q_OBJECT
         private:
          Bottles m_bottleList;
        }
        <in another file>
          ReagentManager m_reagentManager;
          engine->rootContext()->setContextProperty("reagentManager", &m_reagentManager);
        

        In QML:

            onVisibleChanged: {
              if (visible) {
                reagentManager.updateBottleList()
                rack.updateBottles()
              }
            }
        
            // update our QML array based on the C++ model.
            function updateBottles() {
              var modelSize = bottleModel.count
              var i
              var l_color
              var volume
              var minVolume
              var amountNeeded
              var name
        
              for (i = 0; i < modelSize; ++i) {
                name = reagentManager.getName(i)
                bottleRepeater.itemAt(i).cellText = name
        
                volume = reagentManager.m_volume
                minVolume = reagentManager.getMinVolume(i)
                amountNeeded = reagentManager.getAmountNeeded(i)
                l_color = ((volume - minVolume) >= amountNeeded) ? "green" : "red"
                bottleRepeater.itemAt(i).cellColor = l_color
              }
            }
        

        So, my QML function calls C++ routines to obtain the needed data. I'm trying to convert this to the approach you suggested; this is where I ran into the problem with the struct.

        I still don't see where the QVariantList comes into play, though.

        kshegunovK Offline
        kshegunovK Offline
        kshegunov
        Moderators
        wrote on last edited by
        #29
        typedef QVector<Bottle> Bottles;
        

        If Bottle is derived from QObject you can't keep it directly in a vector (can't copy the objects). You need to keep Bottle * there.

        Read and abide by the Qt Code of Conduct

        mzimmersM 1 Reply Last reply
        1
        • kshegunovK kshegunov
          typedef QVector<Bottle> Bottles;
          

          If Bottle is derived from QObject you can't keep it directly in a vector (can't copy the objects). You need to keep Bottle * there.

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

          @kshegunov ah. OK, thanks for that. I'll look into making that change, and will report back.

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

            I've changed my QVector to pointers (seems to be working).

            I think I see why my example is so confusing -- in my Bottle Repeater, I'm using a QML ListModel. This ListModel only contains UI-specific information (position, size). Additional informationmust come from an object (ReagentManager) that is exposed via a call to setContextProperty().

            So: do I need to change my model to the instance of ReagentManager, and find another way to access the information currently in my ListModel? Or is there a more clever way to do this?

            Thanks...

            kshegunovK 1 Reply Last reply
            0
            • mzimmersM mzimmers

              I've changed my QVector to pointers (seems to be working).

              I think I see why my example is so confusing -- in my Bottle Repeater, I'm using a QML ListModel. This ListModel only contains UI-specific information (position, size). Additional informationmust come from an object (ReagentManager) that is exposed via a call to setContextProperty().

              So: do I need to change my model to the instance of ReagentManager, and find another way to access the information currently in my ListModel? Or is there a more clever way to do this?

              Thanks...

              kshegunovK Offline
              kshegunovK Offline
              kshegunov
              Moderators
              wrote on last edited by
              #32

              @mzimmers said in updating elements in a repeater?:

              So: do I need to change my model to the instance of ReagentManager, and find another way to access the information currently in my ListModel? Or is there a more clever way to do this?

              Why do you need the ListModel is the question now. Pass the objects vector from the context property (i.e the bottleManager object) directly to the repeater.

              Read and abide by the Qt Code of Conduct

              mzimmersM 1 Reply Last reply
              0
              • kshegunovK kshegunov

                @mzimmers said in updating elements in a repeater?:

                So: do I need to change my model to the instance of ReagentManager, and find another way to access the information currently in my ListModel? Or is there a more clever way to do this?

                Why do you need the ListModel is the question now. Pass the objects vector from the context property (i.e the bottleManager object) directly to the repeater.

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

                @kshegunov said in updating elements in a repeater?:

                Why do you need the ListModel is the question now. Pass the objects vector from the context property (i.e the bottleManager object) directly to the repeater.

                I'm using the list model for UI-specific information:

                  ListModel {
                    id: bottleModel
                
                    ListElement {
                      // position 1
                      x: 400
                      y: 17
                      height: 75
                      width: 75
                    }
                    ...
                

                I could probably put this data in arrays in QML. As I mentioned, I'd prefer not to put it into my C++ as it's purely UI data.

                From my definition of the ReagentManager class:

                class ReagentManager : public QObject {
                  Q_OBJECT
                 public:
                  explicit ReagentManager(QObject *parent = nullptr);
                  Bottles m_bottleList;
                  Q_PROPERTY(Bottles bottleList MEMBER m_bottleList)
                  ...
                

                And in my QML:

                    function updateBottles() {
                      var modelSize = bottleModel.count
                      var i
                      var volume
                
                      for (i = 0; i < modelSize; ++i) {
                        volume = reagentManager.bottleList[i].volume
                    ...
                

                I'm getting an error "TypeError: Cannot read property '0' of undefined." Is my syntax wrong, or am I still not understanding how to access the property?

                Thanks...

                EDIT: looking at the QML Debugger Console, I see this message:

                QMetaProperty::read: Unable to handle unregistered datatype 'Bottles' for property 'ReagentManager::bottleList'
                
                kshegunovK 1 Reply Last reply
                0
                • mzimmersM mzimmers

                  @kshegunov said in updating elements in a repeater?:

                  Why do you need the ListModel is the question now. Pass the objects vector from the context property (i.e the bottleManager object) directly to the repeater.

                  I'm using the list model for UI-specific information:

                    ListModel {
                      id: bottleModel
                  
                      ListElement {
                        // position 1
                        x: 400
                        y: 17
                        height: 75
                        width: 75
                      }
                      ...
                  

                  I could probably put this data in arrays in QML. As I mentioned, I'd prefer not to put it into my C++ as it's purely UI data.

                  From my definition of the ReagentManager class:

                  class ReagentManager : public QObject {
                    Q_OBJECT
                   public:
                    explicit ReagentManager(QObject *parent = nullptr);
                    Bottles m_bottleList;
                    Q_PROPERTY(Bottles bottleList MEMBER m_bottleList)
                    ...
                  

                  And in my QML:

                      function updateBottles() {
                        var modelSize = bottleModel.count
                        var i
                        var volume
                  
                        for (i = 0; i < modelSize; ++i) {
                          volume = reagentManager.bottleList[i].volume
                      ...
                  

                  I'm getting an error "TypeError: Cannot read property '0' of undefined." Is my syntax wrong, or am I still not understanding how to access the property?

                  Thanks...

                  EDIT: looking at the QML Debugger Console, I see this message:

                  QMetaProperty::read: Unable to handle unregistered datatype 'Bottles' for property 'ReagentManager::bottleList'
                  
                  kshegunovK Offline
                  kshegunovK Offline
                  kshegunov
                  Moderators
                  wrote on last edited by kshegunov
                  #34

                  @mzimmers said in updating elements in a repeater?:

                  I could probably put this data in arrays in QML. As I mentioned, I'd prefer not to put it into my C++ as it's purely UI data.

                  You already have this data in the c++, you feed it to the JS engine as far as I can see. I'd just tie the cpp backend to the UI stuff and not mess with any intermediate stuff, much less using explicit JS code.

                  Basically like this:

                  Column {
                        Repeater {
                          model: reagentManager.bottleList //< This being a property that holds the list of bottles
                          Bottle {
                            cellX: modelData.x
                            cellY: modelData.y //< Or use some other value, or nothing, however you decide to do it
                            ...
                            volume: modelData.volume //< This binds to the property of the QObject, so when the C++ changes value this updates
                            ...
                          }
                       ...
                  }
                  

                  @mzimmers said in updating elements in a repeater?:

                  I'm getting an error "TypeError: Cannot read property '0' of undefined." Is my syntax wrong, or am I still not understanding how to access the property?
                  Thanks...
                  EDIT: looking at the QML Debugger Console, I see this message:

                  From the method:

                  https://doc.qt.io/qt-5/qqmllistproperty.html
                  or
                  you return QList<QObject *>
                  or
                  you return a QVariantList() << bottle1 << bottle2

                  ... different possibilities.

                  Read and abide by the Qt Code of Conduct

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

                    I've changed my typedef from a QVector to a QList:

                    typedef QList<Bottle *> Bottles;
                    

                    My C++ looks like this (stripped down) now:

                    struct Bottle : public QObject {
                      Q_OBJECT
                      Q_PROPERTY(quint32 volume MEMBER m_volume)
                     public:
                      quint32 m_volume;                // amount in bottle (in uL)
                     signals:
                      void volumeChanged(quint32 m_volume);
                    };
                    typedef QList<Bottle *> Bottles;
                    
                    class ReagentManager : public QObject {
                      Q_OBJECT
                     private:
                      Bottles m_bottleList;
                     public:
                      Q_INVOKABLE Bottles bottleList() { return m_bottleList; }
                      void bottleListChanged();
                    };
                    

                    And this line in QML:

                            volume = reagentManager.bottleList[i].volume
                    

                    Now produces this error:

                    qrc:/qml/Rack.qml:194: TypeError: Cannot read property 'volume' of undefined 
                    

                    So...I've kicked the can a little further down the street, but I'm not home yet. It seems that the QML can now access the QList (agree?), but not its properties. Do I need a getter for this? I thought the idea of getting the properties working properly was to eliminate the need for the getters/setters.

                    ODБOïO 1 Reply Last reply
                    0
                    • mzimmersM mzimmers

                      I've changed my typedef from a QVector to a QList:

                      typedef QList<Bottle *> Bottles;
                      

                      My C++ looks like this (stripped down) now:

                      struct Bottle : public QObject {
                        Q_OBJECT
                        Q_PROPERTY(quint32 volume MEMBER m_volume)
                       public:
                        quint32 m_volume;                // amount in bottle (in uL)
                       signals:
                        void volumeChanged(quint32 m_volume);
                      };
                      typedef QList<Bottle *> Bottles;
                      
                      class ReagentManager : public QObject {
                        Q_OBJECT
                       private:
                        Bottles m_bottleList;
                       public:
                        Q_INVOKABLE Bottles bottleList() { return m_bottleList; }
                        void bottleListChanged();
                      };
                      

                      And this line in QML:

                              volume = reagentManager.bottleList[i].volume
                      

                      Now produces this error:

                      qrc:/qml/Rack.qml:194: TypeError: Cannot read property 'volume' of undefined 
                      

                      So...I've kicked the can a little further down the street, but I'm not home yet. It seems that the QML can now access the QList (agree?), but not its properties. Do I need a getter for this? I thought the idea of getting the properties working properly was to eliminate the need for the getters/setters.

                      ODБOïO Offline
                      ODБOïO Offline
                      ODБOï
                      wrote on last edited by
                      #36

                      @mzimmers said in updating elements in a repeater?:

                      volume = reagentManager.bottleList[i].volume

                      bottleList is a function but you are accessing like an array

                      volume = reagentManager.bottleList()[i]

                      mzimmersM 1 Reply Last reply
                      1
                      • ODБOïO ODБOï

                        @mzimmers said in updating elements in a repeater?:

                        volume = reagentManager.bottleList[i].volume

                        bottleList is a function but you are accessing like an array

                        volume = reagentManager.bottleList()[i]

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

                        @LeLev said in updating elements in a repeater?:

                        @mzimmers said in updating elements in a repeater?:

                        volume = reagentManager.bottleList[i].volume

                        bottleList is a function but you are accessing like an array

                        volume = reagentManager.bottleList()[i]

                        Thanks...I thought this would work:

                         volume = reagentManager.bottleList()[i].volume
                        

                        But I get this error:

                        Error: Unknown method return type: Bottles
                        

                        This goes back to what kshegunov was talking about earlier, but I thought I'd fixed this by changing from a QVector to a QList:

                        typedef QList<Bottle *> Bottles;
                        
                        class ReagentManager : public QObject {
                          Q_OBJECT
                         public:
                          Q_INVOKABLE Bottles bottleList() { return m_bottleList; }
                        

                        I'm still missing something...

                        ODБOïO 1 Reply Last reply
                        0
                        • mzimmersM mzimmers

                          @LeLev said in updating elements in a repeater?:

                          @mzimmers said in updating elements in a repeater?:

                          volume = reagentManager.bottleList[i].volume

                          bottleList is a function but you are accessing like an array

                          volume = reagentManager.bottleList()[i]

                          Thanks...I thought this would work:

                           volume = reagentManager.bottleList()[i].volume
                          

                          But I get this error:

                          Error: Unknown method return type: Bottles
                          

                          This goes back to what kshegunov was talking about earlier, but I thought I'd fixed this by changing from a QVector to a QList:

                          typedef QList<Bottle *> Bottles;
                          
                          class ReagentManager : public QObject {
                            Q_OBJECT
                           public:
                            Q_INVOKABLE Bottles bottleList() { return m_bottleList; }
                          

                          I'm still missing something...

                          ODБOïO Offline
                          ODБOïO Offline
                          ODБOï
                          wrote on last edited by
                          #38

                          @mzimmers said in updating elements in a repeater?:

                          I'm still missing something...

                          i would return a QVariantList to qml instead of the QList<Bottle *>

                          mzimmersM 1 Reply Last reply
                          1
                          • ODБOïO ODБOï

                            @mzimmers said in updating elements in a repeater?:

                            I'm still missing something...

                            i would return a QVariantList to qml instead of the QList<Bottle *>

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

                            @LeLev OK, but...how do I do that? I can't just cast it. Do I have to change my Bottles typedef?

                            Thanks...

                            ODБOïO 1 Reply Last reply
                            0
                            • mzimmersM mzimmers

                              @LeLev OK, but...how do I do that? I can't just cast it. Do I have to change my Bottles typedef?

                              Thanks...

                              ODБOïO Offline
                              ODБOïO Offline
                              ODБOï
                              wrote on last edited by
                              #40

                              Q_INVOKABLE QVariant bottleList() { return QVariant::fromValue(m_bottleList); }

                              mzimmersM 1 Reply Last reply
                              2
                              • mzimmersM mzimmers

                                I know, I'm doing a lousy job of explaining this. in C++:

                                typedef QVector<Bottle> Bottles;
                                class ReagentManager : public QObject {
                                  Q_OBJECT
                                 private:
                                  Bottles m_bottleList;
                                }
                                <in another file>
                                  ReagentManager m_reagentManager;
                                  engine->rootContext()->setContextProperty("reagentManager", &m_reagentManager);
                                

                                In QML:

                                    onVisibleChanged: {
                                      if (visible) {
                                        reagentManager.updateBottleList()
                                        rack.updateBottles()
                                      }
                                    }
                                
                                    // update our QML array based on the C++ model.
                                    function updateBottles() {
                                      var modelSize = bottleModel.count
                                      var i
                                      var l_color
                                      var volume
                                      var minVolume
                                      var amountNeeded
                                      var name
                                
                                      for (i = 0; i < modelSize; ++i) {
                                        name = reagentManager.getName(i)
                                        bottleRepeater.itemAt(i).cellText = name
                                
                                        volume = reagentManager.m_volume
                                        minVolume = reagentManager.getMinVolume(i)
                                        amountNeeded = reagentManager.getAmountNeeded(i)
                                        l_color = ((volume - minVolume) >= amountNeeded) ? "green" : "red"
                                        bottleRepeater.itemAt(i).cellColor = l_color
                                      }
                                    }
                                

                                So, my QML function calls C++ routines to obtain the needed data. I'm trying to convert this to the approach you suggested; this is where I ran into the problem with the struct.

                                I still don't see where the QVariantList comes into play, though.

                                ODБOïO Offline
                                ODБOïO Offline
                                ODБOï
                                wrote on last edited by ODБOï
                                #41

                                this is not directly related but
                                @mzimmers said in updating elements in a repeater?:

                                onVisibleChanged: {
                                if (visible) {
                                reagentManager.updateBottleList()
                                rack.updateBottles()
                                }
                                }

                                are you calling this in your Repeater delegate ? If yes, then i believe you will call this multiple times unnecessarily, one way to verify it in qml is putting a console.log() after or before this call to see how meny time this is called

                                1 Reply Last reply
                                1
                                • ODБOïO ODБOï

                                  Q_INVOKABLE QVariant bottleList() { return QVariant::fromValue(m_bottleList); }

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

                                  @LeLev said in updating elements in a repeater?:

                                  Q_INVOKABLE QVariant bottleList() { return QVariant::fromValue(m_bottleList); }

                                  Well, bless my buttons...that works! But why is bottleList() declared as returning a QVariant, and not a QVariantList?

                                  Regarding your question: the onVisibleChanged isn't in the repeater; it's in the parent Rectangle. This was my way of ensuring that the C++ data in ReagentManager updates itself whenever the view is activated.

                                  ODБOïO 1 Reply Last reply
                                  1
                                  • mzimmersM mzimmers

                                    @LeLev said in updating elements in a repeater?:

                                    Q_INVOKABLE QVariant bottleList() { return QVariant::fromValue(m_bottleList); }

                                    Well, bless my buttons...that works! But why is bottleList() declared as returning a QVariant, and not a QVariantList?

                                    Regarding your question: the onVisibleChanged isn't in the repeater; it's in the parent Rectangle. This was my way of ensuring that the C++ data in ReagentManager updates itself whenever the view is activated.

                                    ODБOïO Offline
                                    ODБOïO Offline
                                    ODБOï
                                    wrote on last edited by
                                    #43

                                    @mzimmers said in updating elements in a repeater?:

                                    Well, bless my buttons...that works!

                                    Nice :)

                                    @mzimmers said in updating elements in a repeater?:

                                    But why is bottleList() declared as returning a QVariant, and not a QVariantList?

                                    I don't have a technical explanation for that really, im used to do that since i saw it somewhere in the docs. But i guess you could return a QVariantList directly. It will be converted to javascript array as explained here https://doc.qt.io/qt-5/qtqml-cppintegration-data.html

                                    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