Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

dynamic number of models



  • 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



  • @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
                        }
                    }
                }
            }
        }
    


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





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



  • @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]



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


Log in to reply