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. dynamic number of models

dynamic number of models

Scheduled Pinned Locked Moved Solved QML and Qt Quick
7 Posts 2 Posters 604 Views 2 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.
  • M Offline
    M Offline
    Marek
    wrote on last edited by Marek
    #1

    Hi
    On QML side I have dynamic number of ListView, each of them needs data from Cpp, is there w way to provide dynamic number of models from Cpp ? Other than having QML ListModel in QML and fetch the data from Cpp by some javascript functions? All ListView require the same model but with different data

    Something like:

    foreach(ccpModel in models) {
       cppModel=new MyModel()
       cppModel->loadData()
       engine->rootContext()->setContextProperty("MyModel1",cppModel)
    }
    

    and when I need different models, delete old one, "unsetContextProperty" or just set it again with the same name "MyModel1" but pointing to different QObject ?

    And how do I tell QML ListView to use this model?

    property var my_model: "MyModel"+number 
    model: my_model
    

    is this doable or do I need javascript and QML ListModel ?

    Best Regards
    Marek

    ODБOïO 1 Reply Last reply
    0
    • M Marek

      Hi
      On QML side I have dynamic number of ListView, each of them needs data from Cpp, is there w way to provide dynamic number of models from Cpp ? Other than having QML ListModel in QML and fetch the data from Cpp by some javascript functions? All ListView require the same model but with different data

      Something like:

      foreach(ccpModel in models) {
         cppModel=new MyModel()
         cppModel->loadData()
         engine->rootContext()->setContextProperty("MyModel1",cppModel)
      }
      

      and when I need different models, delete old one, "unsetContextProperty" or just set it again with the same name "MyModel1" but pointing to different QObject ?

      And how do I tell QML ListView to use this model?

      property var my_model: "MyModel"+number 
      model: my_model
      

      is this doable or do I need javascript and QML ListModel ?

      Best Regards
      Marek

      ODБOïO Offline
      ODБOïO Offline
      ODБOï
      wrote on last edited by ODБOï
      #2

      @Marek you can use QVariantList as list of models in QML if it fits your requirement, however I don't know how efficient this will be with complex/large models.

      class Backend : public QObject
      {
          Q_OBJECT
          Q_PROPERTY(QVariantList models READ models WRITE setModels NOTIFY modelsChanged)
      public:
          explicit Backend(QObject *parent = nullptr);
      
          QVariantList models() const
          {
              return m_models;
          }
          void setModels(QVariantList models)
          {
              if (m_models == models)
                  return;
              m_models = models;
              emit modelsChanged();
          }
      
      signals:
          void modelsChanged();
      private :
          QVariantList m_models;  
      };
      
      
      //--------------------------
         Backend backend;
        
          QVariantList myModels;
          QStringList model1;
          model1 << "item1";
          model1 << "item2";
          model1 << "item3";
          myModels.append(QVariant::fromValue(model1));
      
          QStringList model2;
          model2 << "item7";
          model2 << "item8";
          model2 << "item9";
          myModels.append(QVariant::fromValue(model2));
          backend.setModels(myModels);
      
          engine.rootContext()->setContextProperty("backend",&backend);
      
      //------------------------
       property var _models : backend.models
      
          Connections{
              target: backend
              function onModelsChanged (){
                  _models = backend.models
              }
          }
      
       Column{
              anchors.fill: parent
              spacing: 20
              Repeater{
                  model: 2
                  Rectangle{
                      height: 200
                      width: 300
                      border.width: 1
                      color: "grey"
                      ListView{
                          model: _models[index]
                          anchors.fill: parent
                          delegate: Text {
                              height: 20
                              text: modelData
                          }
                      }
                  }
              }
          }
      
      M 1 Reply Last reply
      1
      • ODБOïO ODБOï

        @Marek you can use QVariantList as list of models in QML if it fits your requirement, however I don't know how efficient this will be with complex/large models.

        class Backend : public QObject
        {
            Q_OBJECT
            Q_PROPERTY(QVariantList models READ models WRITE setModels NOTIFY modelsChanged)
        public:
            explicit Backend(QObject *parent = nullptr);
        
            QVariantList models() const
            {
                return m_models;
            }
            void setModels(QVariantList models)
            {
                if (m_models == models)
                    return;
                m_models = models;
                emit modelsChanged();
            }
        
        signals:
            void modelsChanged();
        private :
            QVariantList m_models;  
        };
        
        
        //--------------------------
           Backend backend;
          
            QVariantList myModels;
            QStringList model1;
            model1 << "item1";
            model1 << "item2";
            model1 << "item3";
            myModels.append(QVariant::fromValue(model1));
        
            QStringList model2;
            model2 << "item7";
            model2 << "item8";
            model2 << "item9";
            myModels.append(QVariant::fromValue(model2));
            backend.setModels(myModels);
        
            engine.rootContext()->setContextProperty("backend",&backend);
        
        //------------------------
         property var _models : backend.models
        
            Connections{
                target: backend
                function onModelsChanged (){
                    _models = backend.models
                }
            }
        
         Column{
                anchors.fill: parent
                spacing: 20
                Repeater{
                    model: 2
                    Rectangle{
                        height: 200
                        width: 300
                        border.width: 1
                        color: "grey"
                        ListView{
                            model: _models[index]
                            anchors.fill: parent
                            delegate: Text {
                                height: 20
                                text: modelData
                            }
                        }
                    }
                }
            }
        
        M Offline
        M Offline
        Marek
        wrote on last edited by
        #3

        @LeLev Thanks for hint
        What if I need some more complex model, I mean instead of
        model1 << "item1"

        data with role names:

        QString model_data="{
                            \"id_role\" : fe_id,
                            \"name_role\" : some_name
                            \"more_role\" : some_data}"
        model1 << model_data;
        

        Would this work? Speed is not required, there won't be many elements in the models

        best,
        Marek

        ODБOïO 1 Reply Last reply
        0
        • M Marek

          @LeLev Thanks for hint
          What if I need some more complex model, I mean instead of
          model1 << "item1"

          data with role names:

          QString model_data="{
                              \"id_role\" : fe_id,
                              \"name_role\" : some_name
                              \"more_role\" : some_data}"
          model1 << model_data;
          

          Would this work? Speed is not required, there won't be many elements in the models

          best,
          Marek

          ODБOïO Offline
          ODБOïO Offline
          ODБOï
          wrote on last edited by
          #4

          see
          https://doc.qt.io/qt-5/qtquick-modelviewsdata-cppmodels.html#:~:text=Models can be defined in,a QObjectList or a QAbstractItemModel.

          M 1 Reply Last reply
          0
          • ODБOïO ODБOï

            see
            https://doc.qt.io/qt-5/qtquick-modelviewsdata-cppmodels.html#:~:text=Models can be defined in,a QObjectList or a QAbstractItemModel.

            M Offline
            M Offline
            Marek
            wrote on last edited by Marek
            #5

            @LeLev Need a little help here
            I'm using QAbstractListModel daily, but this list of models does not work for me.
            It does not report any errors, just does not display anything, If I expose individual model like SingleModel0 to QML it works, but as a list of models it does not.
            Can someone take a look, maybe I'm doing something wrong
            Below individual files
            main.cpp

            #include <QGuiApplication>
            #include <QQmlApplicationEngine>
            #include <QQmlContext>
            #include "backend-models.h"
            #include "single-model.h"
            
            int main(int argc, char *argv[])
            {
                QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
            
                QGuiApplication app(argc, argv);
            
                QVariantList list;
            
                QQmlApplicationEngine engine;
                BackendModels backendModels;
                for(int i=0;i<3;i++) {
                    SingleModel *model=new SingleModel(&app,i);
                    list.append(QVariant::fromValue(model));
                    engine.rootContext()->setContextProperty(QString("SingleModel%1").arg(i),model);
                }
                backendModels.setModels(list);
                engine.rootContext()->setContextProperty("BackendModels",&backendModels);
            
            
                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();
            }
            

            backend-models.h

            #include <QtCore>
            
            class BackendModels : public QObject
            {
                Q_OBJECT
                Q_PROPERTY(QVariantList models READ models WRITE setModels NOTIFY modelsChanged)
            public:
                explicit BackendModels(QObject *parent = nullptr);
            
                QVariantList models() const;
                void setModels(QVariantList models);
            signals:
                void modelsChanged();
            private :
                QVariantList m_models;
            };
            

            backend-models.cpp

            #include "backend-models.h"
            
            BackendModels::BackendModels(QObject *parent):QObject(parent) {
            
            }
            QVariantList BackendModels::models() const {
                return m_models;
            }
            void BackendModels::setModels(QVariantList models)
            {
                if (m_models == models)
                    return;
                m_models = models;
                emit modelsChanged();
            }
            

            single-model.h

            #include <QObject>
            #include <QtCore>
            
            struct SingleDataStruct {
                int     id;
                QString name;
            };
            
            class SingleModel : public QAbstractListModel
            {
                Q_OBJECT
            public:
            
                enum ItemRoles {
                    IdRole = Qt::UserRole + 1,
                    NameRole = Qt::UserRole + 2,
                    RowRole=Qt::UserRole+3
                };
            
                SingleModel(QObject* parent,int idx);
            
                virtual int rowCount(const QModelIndex&) const;
                virtual QVariant data(const QModelIndex &index, int role) const;
                QHash<int, QByteArray> roleNames() const;
                QVariant getRoleData(int role, int row) const;
            
            public slots:
            
            signals:
            private slots:
            
            private:
                QVector<SingleDataStruct*> modelVector;
                QHash<int, QByteArray> roles;
            };
            

            single-model.cpp

            #include "single-model.h"
            
            SingleModel::SingleModel(QObject* parent,int idx) : QAbstractListModel (parent)
            {
                roles[IdRole] = "id_role";
                roles[RowRole] = "row_role";
                roles[NameRole] = "name_role";
            
                SingleDataStruct *p;
                for(int i=0;i<10;i++) {
                    p=new SingleDataStruct;
                    p->id=i*10+idx;
                    p->name=QString("name1_%1").arg(p->id);
                    modelVector.append(p);
                }
            }
            
            int SingleModel::rowCount(const QModelIndex&) const {
                return modelVector.count();
            }
            
            QHash<int, QByteArray> SingleModel::roleNames() const {
                return roles;
            }
            
            QVariant SingleModel::data(const QModelIndex &index, int role) const {
                if(!index.isValid()) {
                    return QVariant();
                }
                if(roles.contains(role) && modelVector.value(index.row(),nullptr)!=nullptr) {
                    return getRoleData(role,index.row());
                }
                return QVariant();
            }
            QVariant SingleModel::getRoleData(int role, int row) const {
                SingleDataStruct *p = modelVector.at(row);
            
                switch(role) {
                case IdRole:
                    return QVariant(p->id);
                case NameRole:
                    return QVariant(p->name);
                case RowRole:
                    return QVariant(row);
                default:
                    qWarning()<<"SingleModel::getRoleData there is no role:" << role;
                }
                return QVariant();
            }
            

            Main.qml

            import QtQuick 2.12
            import QtQuick.Window 2.12
            
            Window {
                visible: true
                width: 640
                height: 480
                title: qsTr("Hello World")
            
            
                ListView {
                    id:listView0
                    anchors.top: parent.top
                    anchors.left: parent.left
                    anchors.right: parent.right
                    height:100
                    orientation: ListView.Horizontal
                    spacing: 20
                    model:BackendModels.models[0]
                    delegate: Rectangle {
                        height:parent.height
                        width:height
                        color:"blue"
                        Text {
                            anchors.fill: parent
                            text: name_role
                        }
                    }
                }
                ListView {
                    id:listView1
                    anchors.top: listView0.bottom
                    anchors.left: parent.left
                    anchors.right: parent.right
                    height:100
                    orientation: ListView.Horizontal
                    spacing: 20
                    model:BackendModels.models[1]
                    delegate: Rectangle {
                        height:parent.height
                        width:height
                        color:"green"
                        Text {
                            anchors.fill: parent
                            text: name_role
                        }
                    }
                }
                ListView {
                    id:listView2
                    anchors.top: listView1.bottom
                    anchors.left: parent.left
                    anchors.right: parent.right
                    height:100
                    orientation: ListView.Horizontal
                    spacing: 20
                    model:BackendModels.models[2]
                    delegate: Rectangle {
                        height:parent.height
                        width:height
                        color:"yellow"
                        Text {
                            anchors.fill: parent
                            text: name_role
                        }
                    }
                }
            }
            

            Best
            Marek

            ODБOïO 1 Reply Last reply
            0
            • M Marek

              @LeLev Need a little help here
              I'm using QAbstractListModel daily, but this list of models does not work for me.
              It does not report any errors, just does not display anything, If I expose individual model like SingleModel0 to QML it works, but as a list of models it does not.
              Can someone take a look, maybe I'm doing something wrong
              Below individual files
              main.cpp

              #include <QGuiApplication>
              #include <QQmlApplicationEngine>
              #include <QQmlContext>
              #include "backend-models.h"
              #include "single-model.h"
              
              int main(int argc, char *argv[])
              {
                  QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
              
                  QGuiApplication app(argc, argv);
              
                  QVariantList list;
              
                  QQmlApplicationEngine engine;
                  BackendModels backendModels;
                  for(int i=0;i<3;i++) {
                      SingleModel *model=new SingleModel(&app,i);
                      list.append(QVariant::fromValue(model));
                      engine.rootContext()->setContextProperty(QString("SingleModel%1").arg(i),model);
                  }
                  backendModels.setModels(list);
                  engine.rootContext()->setContextProperty("BackendModels",&backendModels);
              
              
                  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();
              }
              

              backend-models.h

              #include <QtCore>
              
              class BackendModels : public QObject
              {
                  Q_OBJECT
                  Q_PROPERTY(QVariantList models READ models WRITE setModels NOTIFY modelsChanged)
              public:
                  explicit BackendModels(QObject *parent = nullptr);
              
                  QVariantList models() const;
                  void setModels(QVariantList models);
              signals:
                  void modelsChanged();
              private :
                  QVariantList m_models;
              };
              

              backend-models.cpp

              #include "backend-models.h"
              
              BackendModels::BackendModels(QObject *parent):QObject(parent) {
              
              }
              QVariantList BackendModels::models() const {
                  return m_models;
              }
              void BackendModels::setModels(QVariantList models)
              {
                  if (m_models == models)
                      return;
                  m_models = models;
                  emit modelsChanged();
              }
              

              single-model.h

              #include <QObject>
              #include <QtCore>
              
              struct SingleDataStruct {
                  int     id;
                  QString name;
              };
              
              class SingleModel : public QAbstractListModel
              {
                  Q_OBJECT
              public:
              
                  enum ItemRoles {
                      IdRole = Qt::UserRole + 1,
                      NameRole = Qt::UserRole + 2,
                      RowRole=Qt::UserRole+3
                  };
              
                  SingleModel(QObject* parent,int idx);
              
                  virtual int rowCount(const QModelIndex&) const;
                  virtual QVariant data(const QModelIndex &index, int role) const;
                  QHash<int, QByteArray> roleNames() const;
                  QVariant getRoleData(int role, int row) const;
              
              public slots:
              
              signals:
              private slots:
              
              private:
                  QVector<SingleDataStruct*> modelVector;
                  QHash<int, QByteArray> roles;
              };
              

              single-model.cpp

              #include "single-model.h"
              
              SingleModel::SingleModel(QObject* parent,int idx) : QAbstractListModel (parent)
              {
                  roles[IdRole] = "id_role";
                  roles[RowRole] = "row_role";
                  roles[NameRole] = "name_role";
              
                  SingleDataStruct *p;
                  for(int i=0;i<10;i++) {
                      p=new SingleDataStruct;
                      p->id=i*10+idx;
                      p->name=QString("name1_%1").arg(p->id);
                      modelVector.append(p);
                  }
              }
              
              int SingleModel::rowCount(const QModelIndex&) const {
                  return modelVector.count();
              }
              
              QHash<int, QByteArray> SingleModel::roleNames() const {
                  return roles;
              }
              
              QVariant SingleModel::data(const QModelIndex &index, int role) const {
                  if(!index.isValid()) {
                      return QVariant();
                  }
                  if(roles.contains(role) && modelVector.value(index.row(),nullptr)!=nullptr) {
                      return getRoleData(role,index.row());
                  }
                  return QVariant();
              }
              QVariant SingleModel::getRoleData(int role, int row) const {
                  SingleDataStruct *p = modelVector.at(row);
              
                  switch(role) {
                  case IdRole:
                      return QVariant(p->id);
                  case NameRole:
                      return QVariant(p->name);
                  case RowRole:
                      return QVariant(row);
                  default:
                      qWarning()<<"SingleModel::getRoleData there is no role:" << role;
                  }
                  return QVariant();
              }
              

              Main.qml

              import QtQuick 2.12
              import QtQuick.Window 2.12
              
              Window {
                  visible: true
                  width: 640
                  height: 480
                  title: qsTr("Hello World")
              
              
                  ListView {
                      id:listView0
                      anchors.top: parent.top
                      anchors.left: parent.left
                      anchors.right: parent.right
                      height:100
                      orientation: ListView.Horizontal
                      spacing: 20
                      model:BackendModels.models[0]
                      delegate: Rectangle {
                          height:parent.height
                          width:height
                          color:"blue"
                          Text {
                              anchors.fill: parent
                              text: name_role
                          }
                      }
                  }
                  ListView {
                      id:listView1
                      anchors.top: listView0.bottom
                      anchors.left: parent.left
                      anchors.right: parent.right
                      height:100
                      orientation: ListView.Horizontal
                      spacing: 20
                      model:BackendModels.models[1]
                      delegate: Rectangle {
                          height:parent.height
                          width:height
                          color:"green"
                          Text {
                              anchors.fill: parent
                              text: name_role
                          }
                      }
                  }
                  ListView {
                      id:listView2
                      anchors.top: listView1.bottom
                      anchors.left: parent.left
                      anchors.right: parent.right
                      height:100
                      orientation: ListView.Horizontal
                      spacing: 20
                      model:BackendModels.models[2]
                      delegate: Rectangle {
                          height:parent.height
                          width:height
                          color:"yellow"
                          Text {
                              anchors.fill: parent
                              text: name_role
                          }
                      }
                  }
              }
              

              Best
              Marek

              ODБOïO Offline
              ODБOïO Offline
              ODБOï
              wrote on last edited by ODБOï
              #6

              @Marek said in dynamic number of models:

              model:BackendModels[1]

              BackendModels is your object, you need the Q_PROPERTY models of that object, so please try
              model:BackendModels.models [1]

              M 1 Reply Last reply
              1
              • ODБOïO ODБOï

                @Marek said in dynamic number of models:

                model:BackendModels[1]

                BackendModels is your object, you need the Q_PROPERTY models of that object, so please try
                model:BackendModels.models [1]

                M Offline
                M Offline
                Marek
                wrote on last edited by
                #7

                @LeLev Great it works!
                I have edited and corrected Main.qml in previous post.
                Many Thanks
                Marek

                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