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
QtWS25 Last Chance

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 ECEC
    11 Oct 2023, 17:19

    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?

    S Offline
    S Offline
    sierdzio
    Moderators
    wrote on 12 Oct 2023, 05:21 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(:^

    G 1 Reply Last reply 12 Oct 2023, 15:12
    0
    • S sierdzio
      12 Oct 2023, 05:21

      @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.

      G Offline
      G Offline
      GrecKo
      Qt Champions 2018
      wrote on 12 Oct 2023, 15:12 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 7 Dec 2023, 02:54 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?

        J 1 Reply Last reply 7 Dec 2023, 03:30
        0
        • E ECEC
          7 Dec 2023, 02:54

          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?

          J Offline
          J Offline
          jeremy_k
          wrote on 7 Dec 2023, 03:30 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 7 Dec 2023, 04:16
          1
          • J jeremy_k
            7 Dec 2023, 03:30

            @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 7 Dec 2023, 04:16 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.

            J 1 Reply Last reply 7 Dec 2023, 04:38
            0
            • E ECEC
              7 Dec 2023, 04:16

              @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.

              J Offline
              J Offline
              jeremy_k
              wrote on 7 Dec 2023, 04:38 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 7 Dec 2023, 15:41
              1
              • J jeremy_k
                7 Dec 2023, 04:38

                @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 7 Dec 2023, 15:41 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
                • J Offline
                  J Offline
                  jeremy_k
                  wrote on 7 Dec 2023, 19:47 last edited by jeremy_k 12 Jul 2023, 20:06
                  #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 7 Dec 2023, 22:08
                  0
                  • J jeremy_k
                    7 Dec 2023, 19:47

                    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 7 Dec 2023, 22:08 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!

                    J 1 Reply Last reply 8 Dec 2023, 05:23
                    0
                    • E ECEC
                      7 Dec 2023, 22:08

                      @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!

                      J Offline
                      J Offline
                      jeremy_k
                      wrote on 8 Dec 2023, 05:23 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