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. Binding C++ objects in std::vector to QML components

Binding C++ objects in std::vector to QML components

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
repeaterc++qtbinding
14 Posts 4 Posters 1.9k 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.
  • E Offline
    E Offline
    ECEC
    wrote on last edited by
    #4

    Thanks for the suggestions, I think QList is probably the way to go.
    If I do decide to extend the application such that "Room" objects can be added and removed from the QList, would these changes be reflected on the QML side?

    sierdzioS 1 Reply Last reply
    0
    • E ECEC

      Thanks for the suggestions, I think QList is probably the way to go.
      If I do decide to extend the application such that "Room" objects can be added and removed from the QList, would these changes be reflected on the QML side?

      sierdzioS Offline
      sierdzioS Offline
      sierdzio
      Moderators
      wrote on last edited by
      #5

      @ECEC said in Binding C++ objects in std::vector to QML components:

      Thanks for the suggestions, I think QList is probably the way to go.
      If I do decide to extend the application such that "Room" objects can be added and removed from the QList, would these changes be reflected on the QML side?

      No, QList does not send any change signals. But you can manually replace the list on QML side, then it will work. Something like:

      // QML code
      addNewRoom()
      model = null
      model = myModel
      

      Or, another way to do it is to emit a change signal for your model property. For example:

      // C++ code
      Q_PROPERTY(QList<Room*> myModel READ myModel NOTIFY myModelChanged)
      // In your model changing routine:
      _myModel.append(new Room);
      emit myModelChanged();
      

      At some point, if you need more model functionality, it will be easier to just port the model to a standard QAbstractListModel subclass or something similar.

      (Z(:^

      GrecKoG 1 Reply Last reply
      0
      • sierdzioS sierdzio

        @ECEC said in Binding C++ objects in std::vector to QML components:

        Thanks for the suggestions, I think QList is probably the way to go.
        If I do decide to extend the application such that "Room" objects can be added and removed from the QList, would these changes be reflected on the QML side?

        No, QList does not send any change signals. But you can manually replace the list on QML side, then it will work. Something like:

        // QML code
        addNewRoom()
        model = null
        model = myModel
        

        Or, another way to do it is to emit a change signal for your model property. For example:

        // C++ code
        Q_PROPERTY(QList<Room*> myModel READ myModel NOTIFY myModelChanged)
        // In your model changing routine:
        _myModel.append(new Room);
        emit myModelChanged();
        

        At some point, if you need more model functionality, it will be easier to just port the model to a standard QAbstractListModel subclass or something similar.

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

        Use https://github.com/OlivierLDff/ObjectListModel if you need a dynamic model. It has the API of a QList but expose itself as a QAbstractListModel automagically.

        1 Reply Last reply
        0
        • E Offline
          E Offline
          ECEC
          wrote on last edited by
          #7

          Sorry to reopen this again!
          I've decided to move to a QAbstractListModel subclass as adding/removing Rooms is something that needs to be supported. The Room classes' variables have been registered with Q_PROPERTY, however, they are accessed in the view via the model's roles.

          So, my question is, if these Q_PROPERTY variables are modified, will the view automatically update, or do I need to be responsible for that?

          jeremy_kJ 1 Reply Last reply
          0
          • E ECEC

            Sorry to reopen this again!
            I've decided to move to a QAbstractListModel subclass as adding/removing Rooms is something that needs to be supported. The Room classes' variables have been registered with Q_PROPERTY, however, they are accessed in the view via the model's roles.

            So, my question is, if these Q_PROPERTY variables are modified, will the view automatically update, or do I need to be responsible for that?

            jeremy_kJ Offline
            jeremy_kJ Offline
            jeremy_k
            wrote on last edited by
            #8

            @ECEC said in Binding C++ objects in std::vector to QML components:

            Sorry to reopen this again!
            I've decided to move to a QAbstractListModel subclass as adding/removing Rooms is something that needs to be supported. The Room classes' variables have been registered with Q_PROPERTY, however, they are accessed in the view via the model's roles.

            So, my question is, if these Q_PROPERTY variables are modified, will the view automatically update, or do I need to be responsible for that?

            If I understand the description, no, the property change signal will not trigger a re-read of model roles via QAbstractItemModel::data(). That requires emitting the QAIM:dataChanged() signal.

            Asking a question about code? http://eel.is/iso-c++/testcase/

            E 1 Reply Last reply
            1
            • jeremy_kJ jeremy_k

              @ECEC said in Binding C++ objects in std::vector to QML components:

              Sorry to reopen this again!
              I've decided to move to a QAbstractListModel subclass as adding/removing Rooms is something that needs to be supported. The Room classes' variables have been registered with Q_PROPERTY, however, they are accessed in the view via the model's roles.

              So, my question is, if these Q_PROPERTY variables are modified, will the view automatically update, or do I need to be responsible for that?

              If I understand the description, no, the property change signal will not trigger a re-read of model roles via QAbstractItemModel::data(). That requires emitting the QAIM:dataChanged() signal.

              E Offline
              E Offline
              ECEC
              wrote on last edited by
              #9

              @jeremy_k

              That seems to go against Qt's philosophy of declaratively binding UI elements to their C++ counterparts, but I'm going to assume that to return the entire Room object as a role isn't a good idea.

              So I suppose I'll have to call datachanged() to update the view. Room's data comes externally via a NetworkProcessor class. Would you recommend making changes directly on the Room objects (and then calling datachanged() on the model), or performing all changes via the model? For example, NetworkProcessor could emit a roomUpdated() signal, passing a struct containing a Room's id and relevant data we want to update. And then connect this signal to a slot in the model and do the actual updating of the Room list's objects, etc, there.

              jeremy_kJ 1 Reply Last reply
              0
              • E ECEC

                @jeremy_k

                That seems to go against Qt's philosophy of declaratively binding UI elements to their C++ counterparts, but I'm going to assume that to return the entire Room object as a role isn't a good idea.

                So I suppose I'll have to call datachanged() to update the view. Room's data comes externally via a NetworkProcessor class. Would you recommend making changes directly on the Room objects (and then calling datachanged() on the model), or performing all changes via the model? For example, NetworkProcessor could emit a roomUpdated() signal, passing a struct containing a Room's id and relevant data we want to update. And then connect this signal to a slot in the model and do the actual updating of the Room list's objects, etc, there.

                jeremy_kJ Offline
                jeremy_kJ Offline
                jeremy_k
                wrote on last edited by
                #10

                @ECEC said in Binding C++ objects in std::vector to QML components:

                @jeremy_k

                That seems to go against Qt's philosophy of declaratively binding UI elements to their C++ counterparts, but I'm going to assume that to return the entire Room object as a role isn't a good idea.

                I have seen that strategy work.

                So I suppose I'll have to call datachanged() to update the view. Room's data comes externally via a NetworkProcessor class. Would you recommend making changes directly on the Room objects (and then calling datachanged() on the model), or performing all changes via the model? For example, NetworkProcessor could emit a roomUpdated() signal, passing a struct containing a Room's id and relevant data we want to update. And then connect this signal to a slot in the model and do the actual updating of the Room list's objects, etc, there.

                Either way sounds fine. If the existing code base is large, I tend to vote for harmony.

                Asking a question about code? http://eel.is/iso-c++/testcase/

                E 1 Reply Last reply
                1
                • jeremy_kJ jeremy_k

                  @ECEC said in Binding C++ objects in std::vector to QML components:

                  @jeremy_k

                  That seems to go against Qt's philosophy of declaratively binding UI elements to their C++ counterparts, but I'm going to assume that to return the entire Room object as a role isn't a good idea.

                  I have seen that strategy work.

                  So I suppose I'll have to call datachanged() to update the view. Room's data comes externally via a NetworkProcessor class. Would you recommend making changes directly on the Room objects (and then calling datachanged() on the model), or performing all changes via the model? For example, NetworkProcessor could emit a roomUpdated() signal, passing a struct containing a Room's id and relevant data we want to update. And then connect this signal to a slot in the model and do the actual updating of the Room list's objects, etc, there.

                  Either way sounds fine. If the existing code base is large, I tend to vote for harmony.

                  E Offline
                  E Offline
                  ECEC
                  wrote on last edited by
                  #11

                  @jeremy_k

                  Another concern is the maintainability of the model. I understand it's best practice to make changes to the underlying Room objects via the model. e.g. if Room has an updateConfig() method, the model should have an equivalent updateRoomConfig(id) method. However, this doesn't give much freedom to interact with the Room objects outside of the model. Would it be acceptable to expose the model's Room list to other areas of the system and perhaps have them emit a roomUpdated() signal (attached to a corresponding slot in the model that calls dataChanged()) whenever "displayable" changes are made? I'm really only wanting to use the model as a means to display the data, while leaving ownership to other classes.

                  1 Reply Last reply
                  0
                  • jeremy_kJ Offline
                    jeremy_kJ Offline
                    jeremy_k
                    wrote on last edited by jeremy_k
                    #12

                    Have you considered using QStandardItemModel? I shy away from it for heavy C++ use, but it's very convenient as a low effort, thin wrapper. I don't bother with the subclassing of QStandardItem that the examples usually demonstrate.

                    main.cpp:

                    #include <QGuiApplication>
                    #include <QQmlApplicationEngine>
                    #include <QStandardItemModel>
                    #include <QStandardItem>
                    #include <QObject>
                    
                    int main(int argc, char *argv[])
                    {
                        QGuiApplication app(argc, argv);
                        QStandardItemModel model;
                        QStandardItem item;
                        QObject obj;
                        obj.setObjectName("myObject");
                        item.setData(QVariant::fromValue(&obj), Qt::ItemDataRole::DisplayRole);
                        model.appendRow(&item);
                        QQmlApplicationEngine engine;
                        engine.setInitialProperties({ {"myModel", QVariant::fromValue(&model)} });
                        const QUrl url(u"qrc:/untitled7/Main.qml"_qs);
                        QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed,
                            &app, []() { QCoreApplication::exit(-1); },
                            Qt::QueuedConnection);
                        engine.load(url);
                    
                        return app.exec();
                    }
                    

                    main.qml:

                    import QtQuick
                    import QtQuick.Window
                    
                    Window {
                        id: root
                        width: 640
                        height: 480
                        visible: true
                        property var myModel
                        ListView {
                            anchors.fill: parent
                            model: root.myModel
                            delegate: Text {
                                text: display.objectName
                            }
                        }
                    }
                    

                    Asking a question about code? http://eel.is/iso-c++/testcase/

                    E 1 Reply Last reply
                    0
                    • jeremy_kJ jeremy_k

                      Have you considered using QStandardItemModel? I shy away from it for heavy C++ use, but it's very convenient as a low effort, thin wrapper. I don't bother with the subclassing of QStandardItem that the examples usually demonstrate.

                      main.cpp:

                      #include <QGuiApplication>
                      #include <QQmlApplicationEngine>
                      #include <QStandardItemModel>
                      #include <QStandardItem>
                      #include <QObject>
                      
                      int main(int argc, char *argv[])
                      {
                          QGuiApplication app(argc, argv);
                          QStandardItemModel model;
                          QStandardItem item;
                          QObject obj;
                          obj.setObjectName("myObject");
                          item.setData(QVariant::fromValue(&obj), Qt::ItemDataRole::DisplayRole);
                          model.appendRow(&item);
                          QQmlApplicationEngine engine;
                          engine.setInitialProperties({ {"myModel", QVariant::fromValue(&model)} });
                          const QUrl url(u"qrc:/untitled7/Main.qml"_qs);
                          QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed,
                              &app, []() { QCoreApplication::exit(-1); },
                              Qt::QueuedConnection);
                          engine.load(url);
                      
                          return app.exec();
                      }
                      

                      main.qml:

                      import QtQuick
                      import QtQuick.Window
                      
                      Window {
                          id: root
                          width: 640
                          height: 480
                          visible: true
                          property var myModel
                          ListView {
                              anchors.fill: parent
                              model: root.myModel
                              delegate: Text {
                                  text: display.objectName
                              }
                          }
                      }
                      
                      E Offline
                      E Offline
                      ECEC
                      wrote on last edited by
                      #13

                      @jeremy_k

                      I'm not too sure what benefit you are suggesting QStandardItemModel would have over subclassing QAbstractListModel.

                      I'm happy to use QAbstractListModel, and I think I should bring my previous question about whether to interact with objects via the model or directly, to a new thread.

                      Thanks for your help!

                      jeremy_kJ 1 Reply Last reply
                      0
                      • E ECEC

                        @jeremy_k

                        I'm not too sure what benefit you are suggesting QStandardItemModel would have over subclassing QAbstractListModel.

                        I'm happy to use QAbstractListModel, and I think I should bring my previous question about whether to interact with objects via the model or directly, to a new thread.

                        Thanks for your help!

                        jeremy_kJ Offline
                        jeremy_kJ Offline
                        jeremy_k
                        wrote on last edited by
                        #14

                        @ECEC said in Binding C++ objects in std::vector to QML components:

                        @jeremy_k

                        I'm not too sure what benefit you are suggesting QStandardItemModel would have over subclassing QAbstractListModel.

                        The only advantage is less stuff to write and maintain. I count 6 lines of code above, including headers, specific to the standard item model.

                        Asking a question about code? http://eel.is/iso-c++/testcase/

                        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