Solved 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 dataSomething 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