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. a fresh look at C++ models and QML
Forum Updated to NodeBB v4.3 + New Features

a fresh look at C++ models and QML

Scheduled Pinned Locked Moved Solved QML and Qt Quick
23 Posts 3 Posters 2.0k 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.
  • JoeCFDJ JoeCFD

    @mzimmers

    ListView {
        model: listModel
        delegate: Rectangle {
            height: 100
            width: 100
            color: 'lightblue'
            border.width: 1
        }
    }
    
    JoeCFDJ Offline
    JoeCFDJ Offline
    JoeCFD
    wrote on last edited by JoeCFD
    #6

    @JoeCFD override this func in class ListModel : public QAbstractListModel

    int rowCount( const QModelIndex & parent = QModelIndex() ) const
    {
        if ( nullptr != m_list ) {
            return m_list->size();
        }
        return 0;
    }
    

    you will see rows. That is how model works.

    mzimmersM 1 Reply Last reply
    0
    • JoeCFDJ JoeCFD

      @JoeCFD override this func in class ListModel : public QAbstractListModel

      int rowCount( const QModelIndex & parent = QModelIndex() ) const
      {
          if ( nullptr != m_list ) {
              return m_list->size();
          }
          return 0;
      }
      

      you will see rows. That is how model works.

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

      @JoeCFD I'd already done that:

      int ListModel::rowCount(const QModelIndex &parent) const
      {
          int count;
          // For list models only the root node (an invalid parent) should return the list's size. For all
          // other (valid) parents, rowCount() should return 0 so that it does not become a tree model.
          if (parent.isValid()) {
              count = 0;
          } else {
              count = m_list->size();
          }
          qDebug() << __PRETTY_FUNCTION__ << "returning" << count;
          return count;
      }
      

      The problem was, I hadn't given my ListView a size, so I was creating little tiny rectangles. Now it works:

      ListView {
          Layout.fillHeight: true
          Layout.fillWidth: true
          orientation: ListView.Horizontal
          model: listModel
          delegate: Rectangle {
              height: 100
              width: 100
              color: 'lightblue'
              border.width: 1
          }
      }
      

      Produces this:
      rectangles.JPG

      So, question 1 is answered...thank you. Now, how about question 2?

      1 Reply Last reply
      0
      • mzimmersM mzimmers

        @JoeCFD thank you. (I'd tried that, but it didn't show anything, because I neglected to assign sizing to my ListView...works fine now).

        OK, question #2: Let's say I'd like to display the contents of my list elements in the Rectangle(s). This isn't right:

        Text { text: "value is " + model.nbr + "\ndescription is" + model.description}
        

        What is the preferred method of doing this? Thanks...

        JoeCFDJ Offline
        JoeCFDJ Offline
        JoeCFD
        wrote on last edited by
        #8

        @mzimmers define a role for each item of ListItem. use role to access data.

        Text { text: "value is " + model.nbr + "\ndescription is" + model.description}
        

        will not work.

        JoeCFDJ mzimmersM 2 Replies Last reply
        0
        • JoeCFDJ JoeCFD

          @mzimmers define a role for each item of ListItem. use role to access data.

          Text { text: "value is " + model.nbr + "\ndescription is" + model.description}
          

          will not work.

          JoeCFDJ Offline
          JoeCFDJ Offline
          JoeCFD
          wrote on last edited by JoeCFD
          #9

          @JoeCFD I have this struct

              struct InfoItem
              {
                  QString textColor;
                  QString backgroundColor;
                  QString name;
              };
          

          override

          QHash< int, QByteArray > Your class::roleNames() const
              {
                  QHash< int, QByteArray > roles;
              
                  roles[ Qt::UserRole + 1 ] = "textColor";
                  roles[ Qt::UserRole + 2 ] = "backgroundColor";
                  roles[ Qt::UserRole + 3 ] = "name";
              
                  return roles;
              }
          

          access item in your delegate

          Text {
            text: name
            color: textColor   
          }
          

          find the listview example in qt 6 and I guess it has a struct as well.

          1 Reply Last reply
          0
          • JoeCFDJ JoeCFD

            @mzimmers define a role for each item of ListItem. use role to access data.

            Text { text: "value is " + model.nbr + "\ndescription is" + model.description}
            

            will not work.

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

            @JoeCFD my class contains this:

            enum ListEnums {
                NbrRole = Qt::UserRole,
                DescriptionRole
            };
            
            QHash<int, QByteArray> ListModel::roleNames() const
            {
                QHash<int, QByteArray> names;
                names[NbrRole] = "value";
                names[DescriptionRole] = "description";
                return names;
            }
            

            and my delegate now contains this:

            Text { text: "value is " + nbr + "\ndescription is" + description}
            

            I now get "ReferenceError: nbr is not defined."

            JoeCFDJ 1 Reply Last reply
            0
            • mzimmersM mzimmers

              @JoeCFD my class contains this:

              enum ListEnums {
                  NbrRole = Qt::UserRole,
                  DescriptionRole
              };
              
              QHash<int, QByteArray> ListModel::roleNames() const
              {
                  QHash<int, QByteArray> names;
                  names[NbrRole] = "value";
                  names[DescriptionRole] = "description";
                  return names;
              }
              

              and my delegate now contains this:

              Text { text: "value is " + nbr + "\ndescription is" + description}
              

              I now get "ReferenceError: nbr is not defined."

              JoeCFDJ Offline
              JoeCFDJ Offline
              JoeCFD
              wrote on last edited by
              #11

              @mzimmers
              from your definitions:

              Text { text: "value is " + value + "\ndescription is" + description}
              
              mzimmersM 1 Reply Last reply
              1
              • JoeCFDJ JoeCFD

                @mzimmers
                from your definitions:

                Text { text: "value is " + value + "\ndescription is" + description}
                
                mzimmersM Offline
                mzimmersM Offline
                mzimmers
                wrote on last edited by mzimmers
                #12

                @JoeCFD oh, right - I'm still getting used to that feature of roles...thanks for the correction.

                Now, I have a timer that goes off once a second, and signals this slot:

                void ListModel::update()
                {
                    for (int i = 0; i < m_list->size(); ++i) {
                        int newNbr = m_list->at(i).nbr + 1;
                        QModelIndex qmi = index(i, 0, QModelIndex());
                        setData(qmi, newNbr, NbrRole);
                    }
                }
                

                My setData function:

                bool ListModel::setData(const QModelIndex &index, const QVariant &value, int role)
                {
                    bool rc = false;
                
                    do {
                        if (m_list == nullptr) {
                            continue;
                        }
                
                        ListItem item = m_list->at(index.row());
                        switch (role) {
                        case NbrRole:
                            item.nbr = value.toInt();
                            break;
                        case DescriptionRole:
                            item.description = value.toString();
                            break;
                        }
                
                        if (data(index, role) != value) {
                            // how best to change the item in the list here?
                            emit dataChanged(index, index, {role});
                            rc = true;
                        }
                    } while (false);
                    return rc;
                }
                

                I have used the debugger to verify that everything is working as expected. All that's missing (I think) is how to actually make the change to the list.

                Question 3: should I just use a QList::replace(), or is there a better way to do it?

                EDIT:

                I've replaced the above:

                int newNbr = m_list->at(i).nbr + 1;
                

                with:

                int newNbr = data(qmi, NbrRole).toInt() + 1;
                

                Might as well get with the program, right?

                mzimmersM 1 Reply Last reply
                0
                • mzimmersM mzimmers

                  @JoeCFD oh, right - I'm still getting used to that feature of roles...thanks for the correction.

                  Now, I have a timer that goes off once a second, and signals this slot:

                  void ListModel::update()
                  {
                      for (int i = 0; i < m_list->size(); ++i) {
                          int newNbr = m_list->at(i).nbr + 1;
                          QModelIndex qmi = index(i, 0, QModelIndex());
                          setData(qmi, newNbr, NbrRole);
                      }
                  }
                  

                  My setData function:

                  bool ListModel::setData(const QModelIndex &index, const QVariant &value, int role)
                  {
                      bool rc = false;
                  
                      do {
                          if (m_list == nullptr) {
                              continue;
                          }
                  
                          ListItem item = m_list->at(index.row());
                          switch (role) {
                          case NbrRole:
                              item.nbr = value.toInt();
                              break;
                          case DescriptionRole:
                              item.description = value.toString();
                              break;
                          }
                  
                          if (data(index, role) != value) {
                              // how best to change the item in the list here?
                              emit dataChanged(index, index, {role});
                              rc = true;
                          }
                      } while (false);
                      return rc;
                  }
                  

                  I have used the debugger to verify that everything is working as expected. All that's missing (I think) is how to actually make the change to the list.

                  Question 3: should I just use a QList::replace(), or is there a better way to do it?

                  EDIT:

                  I've replaced the above:

                  int newNbr = m_list->at(i).nbr + 1;
                  

                  with:

                  int newNbr = data(qmi, NbrRole).toInt() + 1;
                  

                  Might as well get with the program, right?

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

                  OK, this is getting interesting now (at least to me).

                  Back to my original app, the app receives messages containing information to be used for updating the model. I now see that I need to use data() and setData() for this, but...

                  Question 4: if there are multiple changes to a given list entry, do I have to handle each one individually (as in the example below), or is there some way to do this automatically? I notice there's a setItemData() function, but I'm not sure how to handle the fact that my roles pertain to different data types. Here's my snippet:

                  // create a temporary item from the new values from the back end.
                  EquipmentItem item(uuid, equipName, fwVersion, modelId, serialNumber, powerControllable, state);
                  
                  // create a QModelIndex for the data()/setData() calls.
                  QModelIndex qmi = index(listIndex, 0, QModelIndex());
                  
                  listIndex = getIndex(uuid);
                      EquipmentItem itemFromList = m_list->at(listIndex);
                      if (itemFromList == item) {
                          // do nothing; no change.
                      } else {
                          // do I have to do this for each item in the struct?
                          if (data(qmi, UuidRole).toUuid() != item.m_uuid) {
                              setData(qmi, item.m_uuid, UuidRole);
                          }
                      }
                  }
                  

                  Thanks...

                  JoeCFDJ 1 Reply Last reply
                  0
                  • mzimmersM mzimmers

                    OK, this is getting interesting now (at least to me).

                    Back to my original app, the app receives messages containing information to be used for updating the model. I now see that I need to use data() and setData() for this, but...

                    Question 4: if there are multiple changes to a given list entry, do I have to handle each one individually (as in the example below), or is there some way to do this automatically? I notice there's a setItemData() function, but I'm not sure how to handle the fact that my roles pertain to different data types. Here's my snippet:

                    // create a temporary item from the new values from the back end.
                    EquipmentItem item(uuid, equipName, fwVersion, modelId, serialNumber, powerControllable, state);
                    
                    // create a QModelIndex for the data()/setData() calls.
                    QModelIndex qmi = index(listIndex, 0, QModelIndex());
                    
                    listIndex = getIndex(uuid);
                        EquipmentItem itemFromList = m_list->at(listIndex);
                        if (itemFromList == item) {
                            // do nothing; no change.
                        } else {
                            // do I have to do this for each item in the struct?
                            if (data(qmi, UuidRole).toUuid() != item.m_uuid) {
                                setData(qmi, item.m_uuid, UuidRole);
                            }
                        }
                    }
                    

                    Thanks...

                    JoeCFDJ Offline
                    JoeCFDJ Offline
                    JoeCFD
                    wrote on last edited by
                    #14

                    @mzimmers

                            ListItem item = m_list->at(index.row());  <=== this is a copy. nothing has been changed in your model.
                            switch (role) {
                            case NbrRole:
                                item.nbr = value.toInt();
                                break;
                            case DescriptionRole:
                                item.description = value.toString();
                                break;
                            }
                    
                    mzimmersM 1 Reply Last reply
                    0
                    • JoeCFDJ JoeCFD

                      @mzimmers

                              ListItem item = m_list->at(index.row());  <=== this is a copy. nothing has been changed in your model.
                              switch (role) {
                              case NbrRole:
                                  item.nbr = value.toInt();
                                  break;
                              case DescriptionRole:
                                  item.description = value.toString();
                                  break;
                              }
                      
                      mzimmersM Offline
                      mzimmersM Offline
                      mzimmers
                      wrote on last edited by
                      #15

                      @JoeCFD I see your comment. So, I've added the following line in order to modify my model:

                      ListItem item = m_list->at(index.row());
                      switch (role) {
                      case NbrRole:
                          item.nbr = value.toInt();
                          break;
                      case DescriptionRole:
                          item.description = value.toString();
                          break;
                      }
                      
                      if (data(index, role) != value) {
                          int row = index.row();
                          m_list->replace(row, item); // <== changes the model, right?
                          emit dataChanged(index, index, {role});
                          rc = true;
                      }
                      

                      This appears to work. My concern is, if my updating routine changes several elements in the struct, I end up calling setData() several times, which could be inefficient in a larger example. Hence my question #4: is there a way to "group" the changes before I replace the item in my list? It appears that setItemData() would accomplish this, but I'm not sure how to use it (the doc is fairly terse).

                      GrecKoG 1 Reply Last reply
                      0
                      • mzimmersM mzimmers

                        @JoeCFD I see your comment. So, I've added the following line in order to modify my model:

                        ListItem item = m_list->at(index.row());
                        switch (role) {
                        case NbrRole:
                            item.nbr = value.toInt();
                            break;
                        case DescriptionRole:
                            item.description = value.toString();
                            break;
                        }
                        
                        if (data(index, role) != value) {
                            int row = index.row();
                            m_list->replace(row, item); // <== changes the model, right?
                            emit dataChanged(index, index, {role});
                            rc = true;
                        }
                        

                        This appears to work. My concern is, if my updating routine changes several elements in the struct, I end up calling setData() several times, which could be inefficient in a larger example. Hence my question #4: is there a way to "group" the changes before I replace the item in my list? It appears that setItemData() would accomplish this, but I'm not sure how to use it (the doc is fairly terse).

                        GrecKoG Offline
                        GrecKoG Offline
                        GrecKo
                        Qt Champions 2018
                        wrote on last edited by
                        #16

                        You generally don't call setData inside your own logic code.
                        Just change the underlying data and emit dataChanged for the relevant index and roles.

                        setData is there when you want to let your views update your model. For example if you wanted to have a TextField in your delegate to modify the description of one of your element.

                        mzimmersM 1 Reply Last reply
                        1
                        • GrecKoG GrecKo

                          You generally don't call setData inside your own logic code.
                          Just change the underlying data and emit dataChanged for the relevant index and roles.

                          setData is there when you want to let your views update your model. For example if you wanted to have a TextField in your delegate to modify the description of one of your element.

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

                          @GrecKo I see. So then, my updating routine would look like this:

                          QList<int> changedRoles;
                          ListItem item;
                          
                          for (int i = 0; i < m_list->size(); ++i) {
                              QModelIndex qmi = index(i, 0, QModelIndex());
                          
                              // initialize my temporary item from the model.
                              item.nbr = m_list->at(i).nbr;
                              item.description = m_list->at(i).description;
                          
                              // update the temporary item.
                              item.nbr++;
                              changedRoles.append(NbrRole);
                          
                              QChar qc = QChar(item.nbr + 0x40);
                              item.description.append(qc);
                              changedRoles.append(DescriptionRole);
                          
                              // replace the list item.
                              m_list->replace(i, item);
                              emit dataChanged(qmi, qmi, changedRoles);
                          }
                          

                          And, to return to my question #4, I guess this solves the problem of multiple replaces and signals.

                          So, does this look about right? Any room for improvement?

                          Thanks...

                          GrecKoG 1 Reply Last reply
                          0
                          • mzimmersM mzimmers

                            @GrecKo I see. So then, my updating routine would look like this:

                            QList<int> changedRoles;
                            ListItem item;
                            
                            for (int i = 0; i < m_list->size(); ++i) {
                                QModelIndex qmi = index(i, 0, QModelIndex());
                            
                                // initialize my temporary item from the model.
                                item.nbr = m_list->at(i).nbr;
                                item.description = m_list->at(i).description;
                            
                                // update the temporary item.
                                item.nbr++;
                                changedRoles.append(NbrRole);
                            
                                QChar qc = QChar(item.nbr + 0x40);
                                item.description.append(qc);
                                changedRoles.append(DescriptionRole);
                            
                                // replace the list item.
                                m_list->replace(i, item);
                                emit dataChanged(qmi, qmi, changedRoles);
                            }
                            

                            And, to return to my question #4, I guess this solves the problem of multiple replaces and signals.

                            So, does this look about right? Any room for improvement?

                            Thanks...

                            GrecKoG Offline
                            GrecKoG Offline
                            GrecKo
                            Qt Champions 2018
                            wrote on last edited by
                            #18

                            @mzimmers That's not how I would write it.
                            Your for loop is quite synthetic but here's how I would do the same

                            for (ListItem& item : m_list) { // use range for loop, also get a reference to your items in your list
                                item.nbr++; // edit the item reference in place
                                QChar qc = QChar(item.nbr + 0x40); // ? not sure what you wanted to do there but I copied it
                                item.description.append(qc);
                            }
                            // if you modify contiguous items at the same time, emit dataChanged once for all the range.
                            emit dataChanged(index(0), index(m_list.size() - 1), {NbrRole, DescriptionRole});
                            
                            mzimmersM 1 Reply Last reply
                            0
                            • GrecKoG GrecKo

                              @mzimmers That's not how I would write it.
                              Your for loop is quite synthetic but here's how I would do the same

                              for (ListItem& item : m_list) { // use range for loop, also get a reference to your items in your list
                                  item.nbr++; // edit the item reference in place
                                  QChar qc = QChar(item.nbr + 0x40); // ? not sure what you wanted to do there but I copied it
                                  item.description.append(qc);
                              }
                              // if you modify contiguous items at the same time, emit dataChanged once for all the range.
                              emit dataChanged(index(0), index(m_list.size() - 1), {NbrRole, DescriptionRole});
                              
                              mzimmersM Offline
                              mzimmersM Offline
                              mzimmers
                              wrote on last edited by mzimmers
                              #19

                              @GrecKo I like some things about your approach better than mine, but it leaves a small issue: without a conventional loop, how do I know what row I'm working on?

                              In my real app, the updates are conditional; it would look a little more like this:

                              QList<int> changedRoles;
                              
                              for (ListItem &item: *m_list) {
                                      QModelIndex qmi = index(i, 0, QModelIndex()); // how to get row?
                              
                                  if (something) {
                                      item.nbr++;
                                      changedRoles.append(NbrRole);
                                  }
                                  if (something else) {
                                      QChar qc = QChar(item.nbr + 0x40;
                                      item.description.append(qc);
                                      changedRoles.append(DescriptionRole);
                                  }
                                  if (changedRoles.size() > 0) {
                                      emit dataChanged(qmi, qmi, changedRoles);
                                  }
                              }
                              

                              Is there some magic way to get the row number from within your loop, so I can create a QModelIndex for the signal?

                              Thanks...

                              EDIT:

                              Evidently, C++20 would give me the ability to do what I was asking for, but since I'm using C++17, I guess I can just do it manually:

                              void ListModel::update()
                              {
                                  QList<int> changedRoles;
                                  int row;
                              
                                  row = 0;
                              
                                  for (ListItem &item: *m_list) {
                                      QModelIndex qmi = index(row, 0, QModelIndex());
                              
                                      // update the temporary item.
                                      item.nbr++;
                                      changedRoles.append(NbrRole);
                              
                                      QChar qc = QChar(item.nbr + 0x40);
                                      item.description.append(qc);
                                      changedRoles.append(DescriptionRole);
                              
                                      if (changedRoles.size() > 0) {
                                          emit dataChanged(qmi, qmi, changedRoles);
                                      }
                                      row++;
                                  }
                              }
                              

                              @GrecKo I saw your comment about minimizing signals if contiguous items are changed, but in my real app, that's rarely going to be the case, and I think trying to reduce the number of signals would complicate the logic, so I'll probably leave that part as it is. Apart from this, how does this look to you?

                              mzimmersM 1 Reply Last reply
                              1
                              • mzimmersM mzimmers

                                @GrecKo I like some things about your approach better than mine, but it leaves a small issue: without a conventional loop, how do I know what row I'm working on?

                                In my real app, the updates are conditional; it would look a little more like this:

                                QList<int> changedRoles;
                                
                                for (ListItem &item: *m_list) {
                                        QModelIndex qmi = index(i, 0, QModelIndex()); // how to get row?
                                
                                    if (something) {
                                        item.nbr++;
                                        changedRoles.append(NbrRole);
                                    }
                                    if (something else) {
                                        QChar qc = QChar(item.nbr + 0x40;
                                        item.description.append(qc);
                                        changedRoles.append(DescriptionRole);
                                    }
                                    if (changedRoles.size() > 0) {
                                        emit dataChanged(qmi, qmi, changedRoles);
                                    }
                                }
                                

                                Is there some magic way to get the row number from within your loop, so I can create a QModelIndex for the signal?

                                Thanks...

                                EDIT:

                                Evidently, C++20 would give me the ability to do what I was asking for, but since I'm using C++17, I guess I can just do it manually:

                                void ListModel::update()
                                {
                                    QList<int> changedRoles;
                                    int row;
                                
                                    row = 0;
                                
                                    for (ListItem &item: *m_list) {
                                        QModelIndex qmi = index(row, 0, QModelIndex());
                                
                                        // update the temporary item.
                                        item.nbr++;
                                        changedRoles.append(NbrRole);
                                
                                        QChar qc = QChar(item.nbr + 0x40);
                                        item.description.append(qc);
                                        changedRoles.append(DescriptionRole);
                                
                                        if (changedRoles.size() > 0) {
                                            emit dataChanged(qmi, qmi, changedRoles);
                                        }
                                        row++;
                                    }
                                }
                                

                                @GrecKo I saw your comment about minimizing signals if contiguous items are changed, but in my real app, that's rarely going to be the case, and I think trying to reduce the number of signals would complicate the logic, so I'll probably leave that part as it is. Apart from this, how does this look to you?

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

                                Time for question #5:

                                I think I have my model working correctly now. I use it in a couple of QML screens. One works fine (I can get the fields I need):

                                ListView {
                                    model: spaceModel
                                    delegate: SpaceCard {
                                        titleText: name // one of my role names
                                

                                and the name shows up in the SpaceCard just fine.

                                When I try to use it like this, though:

                                TabBar {
                                    Repeater {
                                        model: spaceModel
                                        delegate: TabButton {
                                            contentItem: Text {
                                                text: name // one of my role names
                                

                                The name field remains blank. Could this be because I'm using a repeater to populate my TabBar -- from the docs:

                                The Repeater type creates all of its delegate items when the repeater is first created.

                                This idea doesn't really hold water, because my tab bar is indeed updating (verified by prepending a string to my "name" field, but...I can't think of anything else. Any ideas why this might not be properly populating the name field?

                                Thanks...

                                JoeCFDJ mzimmersM 2 Replies Last reply
                                0
                                • mzimmersM mzimmers

                                  Time for question #5:

                                  I think I have my model working correctly now. I use it in a couple of QML screens. One works fine (I can get the fields I need):

                                  ListView {
                                      model: spaceModel
                                      delegate: SpaceCard {
                                          titleText: name // one of my role names
                                  

                                  and the name shows up in the SpaceCard just fine.

                                  When I try to use it like this, though:

                                  TabBar {
                                      Repeater {
                                          model: spaceModel
                                          delegate: TabButton {
                                              contentItem: Text {
                                                  text: name // one of my role names
                                  

                                  The name field remains blank. Could this be because I'm using a repeater to populate my TabBar -- from the docs:

                                  The Repeater type creates all of its delegate items when the repeater is first created.

                                  This idea doesn't really hold water, because my tab bar is indeed updating (verified by prepending a string to my "name" field, but...I can't think of anything else. Any ideas why this might not be properly populating the name field?

                                  Thanks...

                                  JoeCFDJ Offline
                                  JoeCFDJ Offline
                                  JoeCFD
                                  wrote on last edited by
                                  #21

                                  @mzimmers I guess this will work as well.

                                  void ListModel::update()
                                  {
                                      QList<int> changedRoles;
                                      int row{ 0 };
                                      for (ListItem &item: *m_list) {
                                          QModelIndex qmi = index(row++, 0, QModelIndex());
                                  
                                          // update the temporary item.
                                          item.nbr++;
                                          changedRoles.append(NbrRole);
                                  
                                          QChar qc = QChar(item.nbr + 0x40);
                                          item.description.append(qc);
                                          changedRoles.append(DescriptionRole);
                                  
                                          if (changedRoles.size() > 0) {
                                              emit dataChanged(qmi, qmi, changedRoles);
                                          }
                                      }
                                  }
                                  
                                  1 Reply Last reply
                                  0
                                  • mzimmersM mzimmers

                                    Time for question #5:

                                    I think I have my model working correctly now. I use it in a couple of QML screens. One works fine (I can get the fields I need):

                                    ListView {
                                        model: spaceModel
                                        delegate: SpaceCard {
                                            titleText: name // one of my role names
                                    

                                    and the name shows up in the SpaceCard just fine.

                                    When I try to use it like this, though:

                                    TabBar {
                                        Repeater {
                                            model: spaceModel
                                            delegate: TabButton {
                                                contentItem: Text {
                                                    text: name // one of my role names
                                    

                                    The name field remains blank. Could this be because I'm using a repeater to populate my TabBar -- from the docs:

                                    The Repeater type creates all of its delegate items when the repeater is first created.

                                    This idea doesn't really hold water, because my tab bar is indeed updating (verified by prepending a string to my "name" field, but...I can't think of anything else. Any ideas why this might not be properly populating the name field?

                                    Thanks...

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

                                    I've played with this, and I'm nearly sure that the problem mentioned in question #5 has to do with the use of the Repeater.

                                    This code:

                                    ColumnLayout {
                                        id: infoScreen
                                        ListView {
                                            Layout.fillHeight: true
                                            Layout.fillWidth: true
                                            model: spaceModel
                                            delegate: Rectangle {
                                                height: 100
                                                width: 100
                                                color: 'lightblue'
                                                border.width: 1
                                                Text { text: "(((" + name + ")))"}
                                            }
                                        }
                                    

                                    Produces this (correct) screen:
                                    info.JPG
                                    But this code (note the parens):

                                    ColumnLayout {
                                        TabBar {
                                            Repeater {
                                                model: spaceModel
                                                delegate: TabButton {
                                                    contentItem: Text {
                                                        text: "(((" + name + ")))"
                                    

                                    Produces this:
                                    spaces.JPG
                                    The empty parens indicate that the new entries into the model are detected in the screen, so...why isn't the name showing up?

                                    Thanks for any ideas...

                                    mzimmersM 1 Reply Last reply
                                    0
                                    • mzimmersM mzimmers

                                      I've played with this, and I'm nearly sure that the problem mentioned in question #5 has to do with the use of the Repeater.

                                      This code:

                                      ColumnLayout {
                                          id: infoScreen
                                          ListView {
                                              Layout.fillHeight: true
                                              Layout.fillWidth: true
                                              model: spaceModel
                                              delegate: Rectangle {
                                                  height: 100
                                                  width: 100
                                                  color: 'lightblue'
                                                  border.width: 1
                                                  Text { text: "(((" + name + ")))"}
                                              }
                                          }
                                      

                                      Produces this (correct) screen:
                                      info.JPG
                                      But this code (note the parens):

                                      ColumnLayout {
                                          TabBar {
                                              Repeater {
                                                  model: spaceModel
                                                  delegate: TabButton {
                                                      contentItem: Text {
                                                          text: "(((" + name + ")))"
                                      

                                      Produces this:
                                      spaces.JPG
                                      The empty parens indicate that the new entries into the model are detected in the screen, so...why isn't the name showing up?

                                      Thanks for any ideas...

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

                                      I came up with a workaround: I use a ListView instead of a repeater:

                                      ListView {
                                          id: spaceRow
                                          orientation: ListView.Horizontal
                                          model: spaceModel
                                          delegate: TabButton {
                                              id: spaceButton
                                              contentItem: Text {
                                                  text: name // from model
                                                  MouseArea {
                                                      anchors.fill: parent
                                                      onClicked: {
                                                          spaceRow.currentIndex = index
                                                          console.log("spaceRow.currentIndex is " + spaceRow.currentIndex)
                                                      }
                                                  }
                                              }
                                          }
                                      }
                                      

                                      Seems to work OK. I think this is a reasonable answer to question #5, though I'd still like to know whether there's a way to accomplish this with a repeater. I also think this topic is long enough, so I'm going to close it out. Thanks to everyone who helped...

                                      1 Reply Last reply
                                      0
                                      • mzimmersM mzimmers has marked this topic as solved on

                                      • Login

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