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.3k 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 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 Offline
              GrecKoG Offline
              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 Offline
                    GrecKoG Offline
                    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 Offline
                          GrecKoG Offline
                          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
                                • KroMignonK KroMignon

                                  @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

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

                                  @KroMignon said in 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.

                                  Thank you. But I think those templates won't help in my case. I haven't found any possibility to build a multi-level model from the template

                                  1 Reply Last reply
                                  0
                                  • P PavloPonomarov

                                    @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 Offline
                                    GrecKoG Offline
                                    GrecKo
                                    Qt Champions 2018
                                    wrote on last edited by
                                    #22

                                    @PavloPonomarov said in Expose C++ Submodel to 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

                                    Maybe you did something wrong there. Not sure about what you said about the slot and dataChanged signal, if that is done in QML, that's definitely not the correct way to do things. Anyway, using QStandardItemModel is fine for very basic PoC, if you need something more, it will get in the way and be more complicated than implementing your own model.

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

                                    Thank you. But I think those templates won't help in my case. I haven't found any possibility to build a multi-level model from the template

                                    If you have a QQmlObjectListModel of A and the class A has a property of type QQmlObjectListModel, you know have a multi-level model. I've done this multiple times.

                                    I can't really help you more than that if you don't post a small self-sufficient code reproducing the problems you met.

                                    P 1 Reply Last reply
                                    0
                                    • GrecKoG GrecKo

                                      @PavloPonomarov said in Expose C++ Submodel to 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

                                      Maybe you did something wrong there. Not sure about what you said about the slot and dataChanged signal, if that is done in QML, that's definitely not the correct way to do things. Anyway, using QStandardItemModel is fine for very basic PoC, if you need something more, it will get in the way and be more complicated than implementing your own model.

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

                                      Thank you. But I think those templates won't help in my case. I haven't found any possibility to build a multi-level model from the template

                                      If you have a QQmlObjectListModel of A and the class A has a property of type QQmlObjectListModel, you know have a multi-level model. I've done this multiple times.

                                      I can't really help you more than that if you don't post a small self-sufficient code reproducing the problems you met.

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

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

                                      Not sure about what you said about the slot and dataChanged signal

                                      I've added a new role for the QVariantMap into my model, but to keep it up-to-date with model changes I had to create a slot connected to dataChanged of the model. It looks like this:

                                      void MyModel::updateMap(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles)
                                          bool changed = false;
                                          if(roles[0] == ItemObject) return; //ItemObject is a role
                                          QVariantMap item = topLeft.data(ItemObject).toMap();
                                          item[roleNames[roles[0]]] = topLeft.data(roles[0]); //roleNames[roles[0]] to get string representation
                                          itemFromIndex(topLeft)->setData(item, ItemObject);
                                      }
                                      

                                      Then I wrote an invokable function to get this map:

                                      QVariant MyModel::getItem(const QModelIndex &index){
                                          return index.data(ItemObject);
                                      }
                                      

                                      And this is where the issue appears. I can call this function from QML, but is will return only current state of the map, without any binding.

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

                                      I can't really help you more than that if you don't post a small self-sufficient code reproducing the problems you met.

                                      I will try to write a small example to my problem

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

                                        Here is the example:

                                        main.cpp

                                        #include <QGuiApplication>
                                        #include <QQmlApplicationEngine>
                                        #include <QQmlContext>
                                        #include "mymodel.h"
                                        
                                        int main(int argc, char *argv[])
                                        {
                                            QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
                                        
                                            QGuiApplication app(argc, argv);
                                        
                                            QQmlApplicationEngine engine;
                                            QQmlContext *context = engine.rootContext();
                                            myModel *model = new myModel();
                                            context->setContextProperty("myModel", model);
                                            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();
                                        }
                                        

                                        mymodel.h

                                        #ifndef MYMODEL_H
                                        #define MYMODEL_H
                                        
                                        #include <QStandardItemModel>
                                        #include <QObject>
                                        #include <QDebug>
                                        
                                        #define ROWS 10
                                        #define NESTED 3
                                        #define SUBITEMS 8
                                        
                                        class myModel : public QStandardItemModel
                                        {
                                            Q_OBJECT
                                        public:
                                            myModel();
                                            void fillModel();
                                        
                                            QVariantMap getObject(const QModelIndex &index);
                                            QVariantMap getObject(QStandardItem *item);
                                            Q_INVOKABLE QVariant getQMLObject(const QModelIndex &index);
                                            Q_INVOKABLE void setValue(const QModelIndex &index, int value);
                                            enum Roles{
                                                Name=Qt::UserRole+1,
                                                Value,
                                                Description,
                                                QMLObject
                                            };
                                        public slots:
                                            void updateObject(const QModelIndex &left, const QModelIndex &right, const QVector<int> &roles);
                                        private:
                                             QHash<int, QByteArray> roleNames;
                                             QHash<int,QVector<QPersistentModelIndex>> m_Objects;
                                        };
                                        
                                        #endif // MYMODEL_H
                                        

                                        mymodel.cpp

                                        #include "mymodel.h"
                                        
                                        myModel::myModel()
                                        {
                                            roleNames[Name] = "name";
                                            roleNames[Value] = "value";
                                            roleNames[Description] = "description";
                                            roleNames[QMLObject] = "qmlObject";
                                            setItemRoleNames(roleNames);
                                            fillModel();
                                            connect(this, &QAbstractItemModel::dataChanged, this, &myModel::updateObject);
                                        }
                                        
                                        void myModel::fillModel()
                                        {
                                            for(int i = 0; i < 3; i++){
                                                QStandardItem *item = new QStandardItem();
                                                item->setData("TreeParameter"+QString::number(i+1), Name);
                                                item->setData(i, Value);
                                                item->setData("Tree item"+QString::number(i+1), Description);
                                                item->setData(getObject(item), QMLObject);
                                                for(int j = 0; j < 8; j++){
                                                    QStandardItem *subItem = new QStandardItem();
                                                    subItem->setData("SubItem"+QString::number(j+1), Name);
                                                    subItem->setData(j, Value);
                                                    subItem->setData("Nested item"+QString::number(j+1), Description);
                                                    subItem->setData(getObject(subItem), QMLObject);
                                                    item->appendRow(subItem);
                                                }
                                                this->appendRow(item);
                                            }
                                            for(int i = 3; i < 10; i++){
                                                QStandardItem *item = new QStandardItem();
                                                item->setData("Parameter"+QString::number(i+1), Name);
                                                item->setData(i, Value);
                                                item->setData("Usual item"+QString::number(i+1), Description);
                                                item->setData(getObject(item), QMLObject);
                                                this->appendRow(item);
                                            }
                                        }
                                        
                                        QVariantMap myModel::getObject(const QModelIndex &index)
                                        {
                                            return getObject(itemFromIndex(index));
                                        }
                                        
                                        QVariantMap myModel::getObject(QStandardItem *item)
                                        {
                                            QVariantMap result;
                                            result[roleNames[Name]] = item->data(Name);
                                            result[roleNames[Value]] = item->data(Value);
                                            result[roleNames[Description]] = item->data(Description);
                                            return result;
                                        }
                                        
                                        QVariant myModel::getQMLObject(const QModelIndex &index)
                                        {
                                            return index.data(QMLObject);
                                        }
                                        
                                        void myModel::setValue(const QModelIndex &index, int value)
                                        {
                                            setData(index, value, Value);
                                        }
                                        
                                        void myModel::updateObject(const QModelIndex &left, const QModelIndex &right, const QVector<int> &roles)
                                        {
                                            if(roles[0] == QMLObject) return;
                                            QVariantMap obj = left.data(QMLObject).toMap();
                                            obj[roleNames[roles[0]]] = left.data(roles[0]);
                                            setData(left, obj, QMLObject);
                                        }
                                        

                                        main.qml

                                        import QtQuick 2.12
                                        import QtQuick.Window 2.12
                                        import QtQuick.Layouts 1.12
                                        import QtQuick.Controls 1.4 as QC1
                                        import QtQuick.Controls 2.12
                                        import QtQml.Models 2.11
                                        
                                        Window {
                                            width: 640
                                            height: 280
                                            visible: true
                                            title: qsTr("Hello World")
                                            RowLayout{
                                                anchors.fill: parent
                                                QC1.TreeView{
                                                    id: tree
                                                    Layout.fillWidth: true;
                                                    Layout.fillHeight: true;
                                                    model: myModel
                                                    selection: ItemSelectionModel{
                                                        id:mySelectionModel
                                                        model: myModel
                                                    }
                                                    itemDelegate: ItemDelegate{
                                                        Text{
                                                            text: styleData.value
                                                        }
                                                        MouseArea{
                                                            anchors.fill: parent
                                                            onClicked:{
                                                                tree.selection.setCurrentIndex(styleData.index,ItemSelectionModel.SelectCurrent);
                                                                target.modelItem = myModel.getQMLObject(styleData.index);
                                                                target.modelIndex = styleData.index;
                                                            }
                                                        }
                                                    }
                                                    QC1.TableViewColumn{
                                                        width: 150
                                                        title: "Name"
                                                        role: "name"
                                                    }
                                                    QC1.TableViewColumn{
                                                        width: 50
                                                        title: "Value"
                                                        role: "value"
                                                        delegate: TextEdit{
                                                            text: styleData ? styleData.value : "";
                                                            Keys.onReturnPressed: {
                                                                focus = false;
                                                                myModel.setValue(styleData.index, text);
                                                            }
                                                        }
                                                    }
                                                    QC1.TableViewColumn{
                                                        width: 150
                                                        title: "Description"
                                                        role: "description"
                                                    }
                                                }
                                                RowLayout{
                                                    id: target
                                                    Layout.fillWidth: true;
                                                    property var modelIndex: false
                                                    property var modelItem: false
                                                    Rectangle{
                                                        implicitHeight: 20
                                                        implicitWidth: 65
                                                        border.color: "black";
                                                        border.width: 1
                                                        TextEdit{
                                                            id: targetValue
                                                            anchors.fill: parent
                                                            horizontalAlignment: Text.AlignHCenter
                                                            verticalAlignment: Text.AlignVCenter
                                                            text: target.modelItem ? target.modelItem.value : "NaN"
                                                            Keys.onReturnPressed: {
                                                                targetValue.focus = false;
                                                                if(target.modelIndex) myModel.setValue(target.modelIndex, targetValue.text);
                                                            }
                                                        }
                                                    }
                                                    TextArea{
                                                        id: targetText
                                                        readOnly: true
                                                        implicitWidth: 130
                                                        wrapMode: Text.Wrap
                                                        text: target.modelItem ? target.modelItem.name : "Nothing yet"
                                                    }
                                                }
                                            }
                                        }
                                        

                                        Guess I'll have to explain it a little bit. When I click an item of the model in TreeView its QMLObject role is sent to target component, where Value is given to TextEdit and Name is given to TextArea along with the QModelIndex of selected item. So when I change the value inside of TextEdit it updates the value in model. The issue here is that if I change the value inside TreeView it won't be updated in TextEdit, because target receives only a copy of QMLObject role through return index.data(QMLObject);. I know about possibility to pass QQmlDMAbstractItemModelData from TreeView to the taget, but I'm trying to bind model item to target directly, this TreeView is only to make this example more clear. Sorry, couldn't think of something smaller, guess I'm too deep in this topic to keep it simple

                                        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