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. Expose C++ Submodel to QML
Forum Updated to NodeBB v4.3 + New Features

Expose C++ Submodel to QML

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
24 Posts 7 Posters 3.1k 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.
  • P Offline
    P Offline
    PavloPonomarov
    wrote on last edited by
    #1

    Hello. I want to display items of the model inherited from QStandardItemModel and its subitems in two different ListViews. How can I expose a submodel to QML?

    S B KroMignonK 3 Replies Last reply
    0
    • P PavloPonomarov

      Hello. I want to display items of the model inherited from QStandardItemModel and its subitems in two different ListViews. How can I expose a submodel to QML?

      S Offline
      S Offline
      shashikumar
      wrote on last edited by
      #2

      @PavloPonomarov if want to expose c++ model to QML then we have do like this in main .cpp

       QStringListModel *m_LisModel=new QStringListModel();
          QQmlContext *context1=engine.rootContext();
          context1->setContextProperty("model1",m_LisModel);
      
      1 Reply Last reply
      0
      • P PavloPonomarov

        Hello. I want to display items of the model inherited from QStandardItemModel and its subitems in two different ListViews. How can I expose a submodel to QML?

        B Offline
        B Offline
        Bob64
        wrote on last edited by
        #3

        @PavloPonomarov Hi, I am not sure if I have understood but what I think you are asking about is the situation where you have a model, where the item data of the model is itself a model. The way to expose this to QML is to wrap the pointer to the sub-model in a QVariant. You can then access the data item of the parent model, using the sub-model's role name, and use that item as the model of a ListView or whatever.

        This SO question might help:

        https://stackoverflow.com/questions/29558138/use-a-qabstractlistmodel-in-another-one

        P 1 Reply Last reply
        1
        • P Offline
          P Offline
          PavloPonomarov
          wrote on last edited by
          #4

          I registered my model using qmlRegisterType. How do I expose the submodel?
          For example I fill my model like this:

              for(int i = 0; i < 5; i++){
                  QStandardItem *item = new QStandardItem;
                  item->setData("Param"+QString::number(i+1), Name);
                  item->setData(i, Value);
                  appendRow(item);
              }
              QStandardItem *item3 = item(2,0);
              for(int i = 0; i < 8; i++){
                  QStandardItem *sub = new QStandardItem;
                  sub->setData("Sub"+QString::number(i), Name);
                  sub->setData(100+i, Value);
                  item3->appendRow(sub);
              }
          

          Now I want to display model items in one ListView and subitems in another ListView. First ListView is no problem

          ListView{
            model: myModel
            delegate: myDelegate{}
          }
          

          But I have problems getting subitems. In C++ I can get QStandardItem* of each subitem, but this type is unknown to QML and will be translated as QVariant(QStandardItem*, ) and can't be used by ListView. I also can't get it from first ListView as its QML model is QQmlDMAbstractItemModelData , I haven't found any way to get its children.

          1 Reply Last reply
          0
          • B Bob64

            @PavloPonomarov Hi, I am not sure if I have understood but what I think you are asking about is the situation where you have a model, where the item data of the model is itself a model. The way to expose this to QML is to wrap the pointer to the sub-model in a QVariant. You can then access the data item of the parent model, using the sub-model's role name, and use that item as the model of a ListView or whatever.

            This SO question might help:

            https://stackoverflow.com/questions/29558138/use-a-qabstractlistmodel-in-another-one

            P Offline
            P Offline
            PavloPonomarov
            wrote on last edited by
            #5

            @Bob64 My bad, I call it submodel but actually I meant subitems, like I noted in example in my previous post. This SO question is one way to do that, but in my case not every item may have subitems or may have different number of subitems. If I'll create a model for subitems and in parent model add role for it, means each model item will have subitems(submodel). Am I right?

            B 1 Reply Last reply
            0
            • P PavloPonomarov

              @Bob64 My bad, I call it submodel but actually I meant subitems, like I noted in example in my previous post. This SO question is one way to do that, but in my case not every item may have subitems or may have different number of subitems. If I'll create a model for subitems and in parent model add role for it, means each model item will have subitems(submodel). Am I right?

              B Offline
              B Offline
              Bob64
              wrote on last edited by
              #6

              @PavloPonomarov Yes, I realised what you meant after your previous post but I didn't have anything clever to respond with I am afraid. I see that you want to be able to expose what is effectively a list of subitems to a ListView as if it were a model. I don't know if there is a way to do that directly (I am a relative newbie and I am not even familiar with QStandardItem), but QML does tend to be quite flexible in terms of what it will admit as a model for a ListView. Perhaps someone with more experience will be able to suggest a way to do it.

              "If I'll create a model for subitems and in parent model add role for it, means each model item will have subitems(submodel). Am I right?"

              Yes, I think that is the same as what I was thinking. But there might be an easier way - I don't know.

              1 Reply Last reply
              1
              • fcarneyF Offline
                fcarneyF Offline
                fcarney
                wrote on last edited by
                #7

                @Bob64
                If you can guarantee the lifetime of an object to always be there then setContextProperty is fine. However, if that object gets deleted then any access to that property from QML will cause the program to crash. For this reason I have started creating C++ objects and then allowing them to be instantiated in QML like so:

                class SomeObject : public QObject // or any QObject based class
                {
                };
                

                Then in main.cpp (or other suitable place):

                qmlRegisterType<SomeObject>("SomeObjects",1,0,"SomeObject");
                

                Then in qml:

                import SomeObjects 1.0
                ~
                SomeObject {
                    id: someobject
                }
                

                Now the lifetime of the object is controlled by the QML code. This may not may not be what you want.

                @PavloPonomarov
                Please post a complete example of the class you are creating. It is difficult to tell what you are trying to expose and where.

                C++ is a perfectly valid school of magic.

                1 Reply Last reply
                1
                • P Offline
                  P Offline
                  PavloPonomarov
                  wrote on last edited by PavloPonomarov
                  #8

                  @fcarney
                  mymodel.h

                  #ifndef MYMODEL_H
                  #define MYMODEL_H
                  
                  #include <QObject>
                  #include <QStandardItemModel>
                  #include <QStandardItem>
                  
                  class MyModel : public QStandardItemModel
                  {
                      Q_OBJECT
                  public:
                      explicit MyModel(QObject *parent = nullptr);
                      enum{
                         Name =Qt::UserRole,
                         Value
                      };
                      Q_INVOKABLE void setValue(const QModelIndex &index, double value);
                      Q_INVOKABLE double getValue(const QModelIndex &index);
                      Q_INVOKABLE QModelIndex getIndex(int row);
                      Q_INVOKABLE QModelIndex getChildIndex(int parentRow, int childRow);
                  
                      Q_INVOKABLE QStandardItem *getItem(int row);
                  
                      QHash<int, QByteArray> roleNames() const override;
                      QVector<MyModel> mItems;
                  
                  
                  signals:
                  
                  };
                  
                  #endif // MYMODEL_H
                  

                  mymodel.cpp

                  #include "mymodel.h"
                  
                  MyModel::MyModel(QObject *parent) : QStandardItemModel(parent)
                  {
                      for(int i = 0; i < 5; i++){
                          QStandardItem *item = new QStandardItem;
                          item->setData("Param"+QString::number(i+1), Name);
                          item->setData(i, Value);
                          appendRow(item);
                      }
                      QStandardItem *item3 = item(2,0);
                      for(int i = 0; i < 8; i++){
                          QStandardItem *sub = new QStandardItem;
                          sub->setData("Sub"+QString::number(i), Name);
                          sub->setData(100+i, Value);
                          item3->appendRow(sub);
                      }
                  }
                  
                  void MyModel::setValue(const QModelIndex &index, double value)
                  {
                      itemFromIndex(index)->setData(value, Value);
                  }
                  
                  double MyModel::getValue(const QModelIndex &index)
                  {
                      return itemFromIndex(index)->data(Value).toDouble();
                  }
                  
                  QModelIndex MyModel::getIndex(int row)
                  {
                      return index(row, 0);
                  }
                  
                  QModelIndex MyModel::getChildIndex(int parentRow, int childRow)
                  {
                      return index(parentRow, 0).child(childRow, 0);
                  }
                  
                  QStandardItem* MyModel::getItem(int row)
                  {
                      return item(row);
                  }
                  
                  QHash<int, QByteArray> MyModel::roleNames() const
                  {
                      QHash<int, QByteArray> names;
                      names[Name] = "name";
                      names[Value] = "value";
                      return names;
                  }
                  

                  main.cpp

                  #include <QGuiApplication>
                  #include <QQmlApplicationEngine>
                  #include "mymodel.h"
                  
                  Q_DECLARE_METATYPE(QStandardItem*)
                  
                  int main(int argc, char *argv[])
                  {
                      QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
                  
                      QGuiApplication app(argc, argv);
                      qRegisterMetaType<QStandardItem*>();
                      qmlRegisterType<MyModel>("test.io.myModel", 1, 0, "MyModel");
                      QQmlApplicationEngine engine;
                      const QUrl url(QStringLiteral("qrc:/main.qml"));
                      QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                                       &app, [url](QObject *obj, const QUrl &objUrl) {
                          if (!obj && url == objUrl)
                              QCoreApplication::exit(-1);
                      }, Qt::QueuedConnection);
                      engine.load(url);
                  
                      return app.exec();
                  }
                  

                  main.qml

                  import QtQuick 2.12
                  import QtQuick.Window 2.12
                  import QtQuick.Dialogs 1.2
                  import QtQuick.Controls 2.12
                  import QtQuick.Controls 1.4
                  import QtQml.Models 2.11
                  import QtQuick.Layouts 1.12
                  
                  import test.io.myModel 1.0
                  
                  Window {
                      id: window
                      width: 410
                      height: 280
                      visible: true
                      property var objects: []
                  
                      MyModel{
                          id: myModel
                      }
                  
                      RowLayout{
                          height: parent.height
                          TableView{
                              id: leftView
                              Layout.fillHeight: true
                              model: myModel
                              TableViewColumn{
                                  title: "Name"
                                  role: "name"
                              }
                              onClicked: {
                                  //MyModel.getItem(row) will return QVariant(QStandardItem*, ) which can't be used as a model
                                  rightView.model =  myModel.getItem(row);
                              }
                          }
                          TableView{
                              id: rightView
                              Layout.fillHeight: true
                              TableViewColumn{
                                  title: "Name"
                                  role: "name"
                              }
                          }
                      }
                  }
                  

                  In this example third model item has subitems. I need to expose them to QML and display in rightView

                  1 Reply Last reply
                  0
                  • fcarneyF Offline
                    fcarneyF Offline
                    fcarney
                    wrote on last edited by
                    #9

                    @PavloPonomarov said in Expose C++ Submodel to QML:

                    QStandardItem

                    I am not sure if this is a good fit for QML. QStandardItem either needs to be subclassed to provide methods to interact with QML. Or create a wrapper model for QStandardItem that will pull data out. You might be better off creating models that return other models to do what you want. Are you just trying to get a list of items inside QStandardItem?

                    https://doc.qt.io/qt-5/qstandarditem.html#subclassing

                    C++ is a perfectly valid school of magic.

                    P 1 Reply Last reply
                    1
                    • fcarneyF fcarney

                      @PavloPonomarov said in Expose C++ Submodel to QML:

                      QStandardItem

                      I am not sure if this is a good fit for QML. QStandardItem either needs to be subclassed to provide methods to interact with QML. Or create a wrapper model for QStandardItem that will pull data out. You might be better off creating models that return other models to do what you want. Are you just trying to get a list of items inside QStandardItem?

                      https://doc.qt.io/qt-5/qstandarditem.html#subclassing

                      P Offline
                      P Offline
                      PavloPonomarov
                      wrote on last edited by
                      #10

                      @fcarney
                      Not only get the list but also use it to bind via Qml delegate item models to other components. In my case I guess wrapper model is not an option because any model item can have subitems and if I'll have to reference submodel inside my model (like @Bob64 mentioned) then each item of my model will have subitems. Guess I should try to subclass QStandardItem.

                      GrecKoG 1 Reply Last reply
                      0
                      • P PavloPonomarov

                        @fcarney
                        Not only get the list but also use it to bind via Qml delegate item models to other components. In my case I guess wrapper model is not an option because any model item can have subitems and if I'll have to reference submodel inside my model (like @Bob64 mentioned) then each item of my model will have subitems. Guess I should try to subclass QStandardItem.

                        GrecKoG Online
                        GrecKoG Online
                        GrecKo
                        Qt Champions 2018
                        wrote on last edited by
                        #11

                        @PavloPonomarov said in Expose C++ Submodel to QML:

                        Guess I should try to subclass QStandardItem.

                        Don't, you will regret it. Implement your own QAbstractListModel instead.
                        QStandardItem* is only good for the most basic of use-case, and even then I won't recommend it because its API is awkward to use.

                        P 2 Replies Last reply
                        1
                        • GrecKoG GrecKo

                          @PavloPonomarov said in Expose C++ Submodel to QML:

                          Guess I should try to subclass QStandardItem.

                          Don't, you will regret it. Implement your own QAbstractListModel instead.
                          QStandardItem* is only good for the most basic of use-case, and even then I won't recommend it because its API is awkward to use.

                          P Offline
                          P Offline
                          PavloPonomarov
                          wrote on last edited by
                          #12
                          This post is deleted!
                          1 Reply Last reply
                          0
                          • GrecKoG GrecKo

                            @PavloPonomarov said in Expose C++ Submodel to QML:

                            Guess I should try to subclass QStandardItem.

                            Don't, you will regret it. Implement your own QAbstractListModel instead.
                            QStandardItem* is only good for the most basic of use-case, and even then I won't recommend it because its API is awkward to use.

                            P Offline
                            P Offline
                            PavloPonomarov
                            wrote on last edited by
                            #13

                            @GrecKo Is there any good example of how to expose QAbstractListModel items from C++ to QML?

                            1 Reply Last reply
                            0
                            • GrecKoG Online
                              GrecKoG Online
                              GrecKo
                              Qt Champions 2018
                              wrote on last edited by
                              #14

                              https://doc.qt.io/qt-5/qtquick-modelviewsdata-cppmodels.html

                              P 1 Reply Last reply
                              1
                              • GrecKoG GrecKo

                                https://doc.qt.io/qt-5/qtquick-modelviewsdata-cppmodels.html

                                P Offline
                                P Offline
                                PavloPonomarov
                                wrote on last edited by
                                #15

                                @GrecKo This article in documentation returns me to the same question I had at the beginning - having QAbstractListModel subclass how do I add subitems to items and expose them to QML? I found only one good example, that additionally to subclassing QAbstractListModel also creates a custom class for items. That means that I'll have to rewrite my whole QStandardItemModel subclass just because QML developers haven't added a better support for multi-level models. Is there no easier way than this?

                                fcarneyF 1 Reply Last reply
                                0
                                • P PavloPonomarov

                                  @GrecKo This article in documentation returns me to the same question I had at the beginning - having QAbstractListModel subclass how do I add subitems to items and expose them to QML? I found only one good example, that additionally to subclassing QAbstractListModel also creates a custom class for items. That means that I'll have to rewrite my whole QStandardItemModel subclass just because QML developers haven't added a better support for multi-level models. Is there no easier way than this?

                                  fcarneyF Offline
                                  fcarneyF Offline
                                  fcarney
                                  wrote on last edited by
                                  #16

                                  @PavloPonomarov Sometimes, when a method is running into brick walls, you have to start over. That is often the fast route. I ran into similar issues with a Python app I wrote. It worked fine for years, but as I tried to add/modify things the ecosystem around my app degraded. It got to the point where it was a roll of the dice to build an exe properly. At that point I realized for longevity I need to rewrite the app in a different development ecosystem. I am now rewriting that app in Qt and C++. It is the faster route, though at first it looks like the long road.

                                  For another app I am writing I have restructured the data models at least 4 or 5 times. I keep running into brick walls. Mostly due to my lack of understanding of the objects being used. You will not doubt discover some really neat approaches by reworking your models. You may even find better ways to approach the problem. In essence that is what programmers do. They figure out how to solve problems. They don't code, they don't use pretty apis that always do what we want them to do. We use duct tape, welding equipment, and super glue to make things do what we want. Sometimes the fumes make us sick, but we muddle through.

                                  Take a hard look at the problem you are trying to solve. Is your mind making this more complex than it is? I always have to take time to rethink approaches. For instance, I was designing a set of classes to handle displaying a tank map on the screen. I was having trouble contemplating how to sync the data with the database. I realized I needed to make the database primary store and have everything else get fed by events from the database. When I did that I realized I can build all my "sub models" as ListModels in QML. I will expose my database as a QML object (QObject) with methods for adding/removing/changing entries in the database. Everything else will flow to the ListModels through signals. I scrapped about 10 C++ classes as a result.

                                  Take a hard look at what classes are in QML and C++ inside Qt. Problems we are having are often already solved by knowing the tools in the toolbox. I don't know how many times I go to look for something and Qt already has a version of it I can use.

                                  C++ is a perfectly valid school of magic.

                                  D 1 Reply Last reply
                                  0
                                  • GrecKoG Online
                                    GrecKoG Online
                                    GrecKo
                                    Qt Champions 2018
                                    wrote on last edited by
                                    #17

                                    having QAbstractListModel subclass how do I add subitems to items and expose them to QML?

                                    Return a list of your subitems in one of your base model role, I don't see the issue here.
                                    Depending on your needs you could return a simple list like a QVariantList or QList<QObject*>, or a proper QAbstractListModel.

                                    P 1 Reply Last reply
                                    2
                                    • fcarneyF fcarney

                                      @PavloPonomarov Sometimes, when a method is running into brick walls, you have to start over. That is often the fast route. I ran into similar issues with a Python app I wrote. It worked fine for years, but as I tried to add/modify things the ecosystem around my app degraded. It got to the point where it was a roll of the dice to build an exe properly. At that point I realized for longevity I need to rewrite the app in a different development ecosystem. I am now rewriting that app in Qt and C++. It is the faster route, though at first it looks like the long road.

                                      For another app I am writing I have restructured the data models at least 4 or 5 times. I keep running into brick walls. Mostly due to my lack of understanding of the objects being used. You will not doubt discover some really neat approaches by reworking your models. You may even find better ways to approach the problem. In essence that is what programmers do. They figure out how to solve problems. They don't code, they don't use pretty apis that always do what we want them to do. We use duct tape, welding equipment, and super glue to make things do what we want. Sometimes the fumes make us sick, but we muddle through.

                                      Take a hard look at the problem you are trying to solve. Is your mind making this more complex than it is? I always have to take time to rethink approaches. For instance, I was designing a set of classes to handle displaying a tank map on the screen. I was having trouble contemplating how to sync the data with the database. I realized I needed to make the database primary store and have everything else get fed by events from the database. When I did that I realized I can build all my "sub models" as ListModels in QML. I will expose my database as a QML object (QObject) with methods for adding/removing/changing entries in the database. Everything else will flow to the ListModels through signals. I scrapped about 10 C++ classes as a result.

                                      Take a hard look at what classes are in QML and C++ inside Qt. Problems we are having are often already solved by knowing the tools in the toolbox. I don't know how many times I go to look for something and Qt already has a version of it I can use.

                                      D Offline
                                      D Offline
                                      Dylan Deng
                                      wrote on last edited by
                                      #18

                                      @fcarney This video shows how to using C++ models with Qt Quick views.
                                      https://doc.qt.io/qt-5/qtquick-modelviewsdata-cppmodels.html

                                      1 Reply Last reply
                                      0
                                      • P PavloPonomarov

                                        Hello. I want to display items of the model inherited from QStandardItemModel and its subitems in two different ListViews. How can I expose a submodel to QML?

                                        KroMignonK Offline
                                        KroMignonK Offline
                                        KroMignon
                                        wrote on last edited by KroMignon
                                        #19

                                        @PavloPonomarov said in Expose C++ Submodel to QML:

                                        How can I expose a submodel to QML?

                                        I never used QStandardItemModel, so my reply is about the title of the topic "Expose C++ submodel to QML".

                                        I use since many years now a template class create by Thomas Boutrou which creates an QAbstractListModel by introspection of the base QObject.
                                        Take a look at Qt QML Models and Qt SuperMacros.

                                        Perhaps this could help you

                                        It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

                                        P 1 Reply Last reply
                                        1
                                        • GrecKoG GrecKo

                                          having QAbstractListModel subclass how do I add subitems to items and expose them to QML?

                                          Return a list of your subitems in one of your base model role, I don't see the issue here.
                                          Depending on your needs you could return a simple list like a QVariantList or QList<QObject*>, or a proper QAbstractListModel.

                                          P Offline
                                          P Offline
                                          PavloPonomarov
                                          wrote on last edited by
                                          #20

                                          @GrecKo Same as for QAbstractListModel I could add such QVariantMap as additional role to QStandardItemModel. I had to create a slot that updates this role on dataChanged signal. Then I was able to get this map in QML. The issue here is that when I return this map from C++ it loses its connection to model and won't be updated in QML when the model is changed

                                          GrecKoG 1 Reply Last reply
                                          0

                                          • Login

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