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

dynamic number of models

Scheduled Pinned Locked Moved Solved QML and Qt Quick
7 Posts 2 Posters 460 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