Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. General talk
  3. Brainstorm
  4. Update C++ list model from QML

Update C++ list model from QML

Scheduled Pinned Locked Moved Solved Brainstorm
11 Posts 4 Posters 2.3k Views
  • 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.
  • JKSHJ JKSH

    @mzimmers said in Passing data structures from QML to C++:

    Here's my attempt to create an Activity instance:

    Activity {}
    

    Use a helper C++ function that returns a default Activity object: https://stackoverflow.com/questions/42797359/how-to-create-new-instance-of-a-q-gadget-struct-in-qml

    mzimmersM Offline
    mzimmersM Offline
    mzimmers
    wrote on last edited by JKSH
    #1

    [Forked from https://forum.qt.io/topic/142156/passing-data-structures-from-qml-to-c --JKSH]

    @JKSH thanks, that solved part of the problem. I can verify that I'm creating an item (and adding it to a QList in C++).

    Somehow, despite my coding my list as per the demo I mentioned earlier, my displays aren't getting updated with the new list element. Any ideas on this?

    1 Reply Last reply
    0
    • mzimmersM mzimmers

      @TomZ I've modified my append function as follows:

      void ActivityModel::appendItem(Activity item)
      {
          Activity newItem = item;
          m_list->appendItem(newItem);
          emit listChanged(m_list);
      }
      

      Using the debugger, I verified that the list now contains the new item. But the view doesn't change.

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

      @mzimmers Try the following and read the doc.

      void ActivityModel::appendItem(Activity item)
      {
          Activity newItem = item;
          beginResetModel();  
          m_list->appendItem(newItem);
          endResetModel();
      }
      
      mzimmersM 1 Reply Last reply
      1
      • TomZT Offline
        TomZT Offline
        TomZ
        wrote on last edited by
        #2

        The simplest answer to this is that you should not try this.

        To add a new listitem from QML, you can have a invokable C++ method you call, but that should not have anything other than default types. Like ints, strings, date etc.
        (Only exception to this is when you pass a class back from QML which was earlier passed into QML from C++).

        So, you can make your append() method simply be the one that instantiates the item on your list, and then emit the signal to indicate the list has been changed.

        mzimmersM 1 Reply Last reply
        0
        • TomZT TomZ

          The simplest answer to this is that you should not try this.

          To add a new listitem from QML, you can have a invokable C++ method you call, but that should not have anything other than default types. Like ints, strings, date etc.
          (Only exception to this is when you pass a class back from QML which was earlier passed into QML from C++).

          So, you can make your append() method simply be the one that instantiates the item on your list, and then emit the signal to indicate the list has been changed.

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

          @TomZ when you say "should not try this," what specifically are you referring to? The tutorial I mentioned above uses a QVector<a_struct> as the basis for its list.

          The tutorial does have a couple curious aspects, though. I've watched it 3 times now (at 50 minutes per!), and I still don't understand why he creates a new C++ class (ToDoList) as the "back end," then references that class in his QML. Isn't the point of a model to insulate the rest of the code from the back end?

          Thanks...

          TomZT 1 Reply Last reply
          0
          • mzimmersM mzimmers

            @TomZ when you say "should not try this," what specifically are you referring to? The tutorial I mentioned above uses a QVector<a_struct> as the basis for its list.

            The tutorial does have a couple curious aspects, though. I've watched it 3 times now (at 50 minutes per!), and I still don't understand why he creates a new C++ class (ToDoList) as the "back end," then references that class in his QML. Isn't the point of a model to insulate the rest of the code from the back end?

            Thanks...

            TomZT Offline
            TomZT Offline
            TomZ
            wrote on last edited by
            #4

            @mzimmers said in Passing data structures from QML to C++:

            when you say "should not try this," what specifically are you referring to?

            The idea to write Q_INVOKABLE void appendItem(Activity item) and the implications of it. Rationale (and solution) I wrote in my previous reply.

            mzimmersM 1 Reply Last reply
            0
            • TomZT TomZ

              @mzimmers said in Passing data structures from QML to C++:

              when you say "should not try this," what specifically are you referring to?

              The idea to write Q_INVOKABLE void appendItem(Activity item) and the implications of it. Rationale (and solution) I wrote in my previous reply.

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

              @TomZ if I understand you, you're objecting to my use of a struct as my list element? Not sure what I'd do instead. Here's the code for appendItem():

              void ActivityModel::appendItem(Activity item)
              {
                  m_list->appendItem(item); // another class with the actual list.
                  emit listChanged(m_list);
              }
              

              Not sure what I'd do differently here. I could modify appendItem() to not have a parameter, but then I don't know how I'd populate the newly-created item in QML.

              Sorry if I sound confused; it's only because I really am.

              TomZT 1 Reply Last reply
              0
              • mzimmersM mzimmers

                @TomZ if I understand you, you're objecting to my use of a struct as my list element? Not sure what I'd do instead. Here's the code for appendItem():

                void ActivityModel::appendItem(Activity item)
                {
                    m_list->appendItem(item); // another class with the actual list.
                    emit listChanged(m_list);
                }
                

                Not sure what I'd do differently here. I could modify appendItem() to not have a parameter, but then I don't know how I'd populate the newly-created item in QML.

                Sorry if I sound confused; it's only because I really am.

                TomZT Offline
                TomZT Offline
                TomZ
                wrote on last edited by TomZ
                #6

                @mzimmers said in Passing data structures from QML to C++:

                if I understand you, you're objecting to my use of a struct as my list element?

                No, I stated you should not have an invokable append() method which has the struct.
                I further stated; "To add a new listitem from QML, you can have a invokable C++ method you call, but that should not have anything other than default types. Like ints, strings, date etc."

                So go ahead and have anything as your list item. Most of us use QObject or string based list-items.

                1 Reply Last reply
                0
                • TomZT Offline
                  TomZT Offline
                  TomZ
                  wrote on last edited by
                  #7

                  Maybe the point can be driven home by simply understanding object ownership.

                  Your list is owned by the model. The QML can read it, but can never directly delete items from your list. The model is the one that creates new items and deletes items. It owns the list and its list-items.

                  So if you want your QML to add a new item somehow, you will still need the model to be the one that instantiates the new list-item. And understand that as soon as the list changes, the view will follow.

                  mzimmersM 1 Reply Last reply
                  0
                  • TomZT TomZ

                    Maybe the point can be driven home by simply understanding object ownership.

                    Your list is owned by the model. The QML can read it, but can never directly delete items from your list. The model is the one that creates new items and deletes items. It owns the list and its list-items.

                    So if you want your QML to add a new item somehow, you will still need the model to be the one that instantiates the new list-item. And understand that as soon as the list changes, the view will follow.

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

                    @TomZ I've modified my append function as follows:

                    void ActivityModel::appendItem(Activity item)
                    {
                        Activity newItem = item;
                        m_list->appendItem(newItem);
                        emit listChanged(m_list);
                    }
                    

                    Using the debugger, I verified that the list now contains the new item. But the view doesn't change.

                    JoeCFDJ 1 Reply Last reply
                    0
                    • mzimmersM mzimmers

                      @TomZ I've modified my append function as follows:

                      void ActivityModel::appendItem(Activity item)
                      {
                          Activity newItem = item;
                          m_list->appendItem(newItem);
                          emit listChanged(m_list);
                      }
                      

                      Using the debugger, I verified that the list now contains the new item. But the view doesn't change.

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

                      @mzimmers Try the following and read the doc.

                      void ActivityModel::appendItem(Activity item)
                      {
                          Activity newItem = item;
                          beginResetModel();  
                          m_list->appendItem(newItem);
                          endResetModel();
                      }
                      
                      mzimmersM 1 Reply Last reply
                      1
                      • JoeCFDJ JoeCFD

                        @mzimmers Try the following and read the doc.

                        void ActivityModel::appendItem(Activity item)
                        {
                            Activity newItem = item;
                            beginResetModel();  
                            m_list->appendItem(newItem);
                            endResetModel();
                        }
                        
                        mzimmersM Offline
                        mzimmersM Offline
                        mzimmers
                        wrote on last edited by
                        #10

                        @JoeCFD that did it. Following the example in the tutorial, I had created this function:

                        void ActivityModel::setList(ActivityList *list)
                        {
                            beginResetModel();
                            if (m_list != nullptr) {
                                m_list->disconnect(this);
                            }
                        
                            m_list = list;
                        
                            if (m_list != nullptr) {
                                connect(m_list, &ActivityList::preItemAppended, this, [=]() {
                                    const int index = m_list->activities().size();
                                    beginInsertRows(QModelIndex(), index, index);
                                });
                                connect(m_list, &ActivityList::postItemAppended, this, [=]() {
                                    endInsertRows();
                                });
                        
                                connect(m_list, &ActivityList::preItemRemoved, this, [=](int index) {
                                    beginRemoveRows(QModelIndex(), index, index);
                                });
                                connect(m_list, &ActivityList::postItemRemoved, this, [=]() {
                                    endRemoveRows();
                                });
                            }
                        
                            endResetModel();
                        }
                        

                        but I guess it didn't get invoked.

                        The tutorial really is confusing in the area where it creates a new class for the list. It adds a level of indirection that makes it harder to understand the interaction between C++ and QML.

                        1 Reply Last reply
                        0
                        • ChronalC Offline
                          ChronalC Offline
                          Chronal
                          wrote on last edited by
                          #11

                          You can use a QAbstractListModel to update the list model from QML. The QAbstractListModel provides an interface for accessing data from a list of items. It can be used to update the list model from QML by using the setData() method.

                          To update the list model from QML, you will need to create a QAbstractListModel subclass and implement the setData() method. The setData() method should take the index of the item to be updated and the new value for the item. You can then call the setData() method from QML to update the list model.

                          For example, if you have a list of strings, you can create a QAbstractListModel subclass and implement the setData() method as follows:

                          void MyListModel::setData(const QModelIndex &index, const QVariant &value, int role)
                          {
                          if (index.isValid() && role == Qt::EditRole) {
                          int row = index.row();
                          QStringList list = data(index, Qt::DisplayRole).toStringList();
                          list[row] = value.toString();
                          setData(index, QVariant::fromValue(list), Qt::DisplayRole);
                          }
                          }

                          You can then call the setData() method from QML to update the list model. For example:

                          MyListModel {
                          id: myListModel
                          // ...
                          }

                          Button {
                          text: "Update List Model"
                          onClicked: {
                          myListModel.setData(myListModel.index(0, 0), "New Value", Qt.EditRole);
                          }
                          }

                          This will update the first item in the list model with the new value.

                          1 Reply Last reply
                          0
                          • mzimmersM mzimmers has marked this topic as unsolved on
                          • 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