QAbstractListModel example with MVVM pattern
-
wrote on 7 Mar 2023, 10:43 last edited by AROH 3 Jul 2023, 10:49
I am trying to display the list of items that comes from QAbstractListModel on a QML List View using the MVVM pattern. To keep it simple my reading/accessing architecture will be something like this-View(QML-ListView)->ViewModel(C++-Binding Properties defined)->Model(C++ read data from DevicesListModel)->DevicesListModel(QAbstractListModel)class.
The DevicesListModel receives items from lower layers.
I am trying with writing a sample but ended up not knowing how to move further, any help in completing the example to achieve the desired result is much helpful.
DeviceListModel.h
#ifndef DEVICESLISTMODEL_H #define DEVICESLISTMODEL_H #pragma once #include <QObject> #include <QAbstractListModel> class QQmlEngine; class QJSEngine; class DevicesListModel : public QAbstractListModel { Q_OBJECT Q_DISABLE_COPY(DevicesListModel) public: enum DeviceModelRoles { NameRole = Qt::UserRole + 1, AddressRole, TypeRole }; static QObject *qobject_singletontype_provider(QQmlEngine *engine, QJSEngine *scriptEngine) { Q_UNUSED(engine) Q_UNUSED(scriptEngine) return new DevicesListModel(); } // Basic functionality: int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; signals: void countChanged(int count); private slots: void devicesChanged(QVariantList devices); public slots: private: explicit DevicesListModel(QObject *parent = nullptr); ~DevicesListModel(); QList<QVariantMap> m_device_list; QHash<int, QByteArray> m_roles; }; #endif // DEVICESLISTMODEL_H
DeviceListModel.cpp
#include "deviceslistmodel.h" #include <QDebug> DevicesListModel::DevicesListModel(QObject *parent) : QAbstractListModel(parent){ //QObject::connect(DeviceDiscovery::instance(), SIGNAL(devicesChanged(QVariantList)), this, SLOT(devicesChanged(QVariantList))); m_roles[NameRole] = "name"; m_roles[AddressRole] = "address"; m_roles[TypeRole] = "type"; } DevicesListModel::~DevicesListModel() { m_device_list.clear(); } int DevicesListModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) return 0; return m_device_list.count(); } QVariant DevicesListModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); QVariantMap device = m_device_list.at(index.row()); switch (role) { case NameRole: { return QVariant::fromValue(device["name"].toString()); } case AddressRole: { return QVariant::fromValue(device["address"].toString()); } case TypeRole: { return QVariant::fromValue(device["type"].toString()); } default: { return QVariant::fromValue(QString("Unkown Role")); } } } void DevicesListModel::devicesChanged(QVariantList devices) { // Add device for (QVariant device: devices) { QVariantMap deviceMap = device.toMap(); QString name = deviceMap["name"].toString(); QString address = deviceMap["address"].toString(); QString type = deviceMap["type"].toString(); qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << name << address << type; if (!m_device_list.contains(deviceMap)) { m_device_list.append(deviceMap); } } // Remove device for (int i = 0; i < m_device_list.count(); i++) { if (!devices.contains(QVariant::fromValue(m_device_list[i]))) { m_device_list.removeAt(i); } } emit countChanged(m_device_list.count()); }
DeviceModel.h
#ifndef DEVICESMODEL_H #define DEVICESMODEL_H #include <QObject> class DevicesModel : public QObject { Q_OBJECT private: QStringList _devicesList; public: virtual ~DevicesModel() {} explicit DevicesModel(QObject *parent = nullptr); //QString getDevicesListModelItems() const {return _devicesList;} void readListItemsFromDeviceListModel(){ //how to read from devicesListModel and Store here, so that View can read the data using properties defined in the deviceViewModel } signals: public slots: }; #endif // DEVICESMODEL_H
DeviceModel.cpp
#include "devicesmodel.h"
DevicesModel::DevicesModel(QObject *parent) : QObject(parent)
{}
DeviceViewModel.h
#ifndef DEVICEVIEWMODEL_H #define DEVICEVIEWMODEL_H #include <QObject> #include <QList> #include "devicesmodel.h" class DeviceViewModel : public QObject { Q_OBJECT private: DevicesModel _devicesModel; //Q_PROPERTY(QList devicesListModel READ devicesListModel WRITE setDevicesListModel NOTIFY devicesListModelChanged) //QList m_devicesListModel; public: explicit DeviceViewModel(const DevicesModel& devicesModel); virtual ~DeviceViewModel(){} //QList devicesListModel() const; signals: //void devicesListModelChanged(QList devicesListModel); public slots: //void setDevicesListModel(QList devicesListModel); }; #endif // DEVICEVIEWMODEL_H
DeviceViewModel.cpp
#include "deviceviewmodel.h" DeviceViewModel::DeviceViewModel(const DevicesModel& devicesModel) { } /*QList DeviceViewModel::devicesListModel() const { return m_devicesListModel; } void DeviceViewModel::setDevicesListModel(QList devicesListModel) { if (m_devicesListModel == devicesListModel) return; m_devicesListModel = devicesListModel; emit devicesListModelChanged(m_devicesListModel); }*/
main.cpp
#include <QGuiApplication> #include <QQmlContext> #include <QQmlApplicationEngine> #include "deviceviewmodel.h" int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); DevicesModel deviceMod; DeviceViewModel deviceViewModell(deviceMod); QQmlApplicationEngine engine; engine.rootContext()->setContextProperty("listModel", &deviceViewModell); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); if (engine.rootObjects().isEmpty()) return -1; return app.exec(); }
main.qml
import QtQuick 2.9 import QtQuick.Window 2.2 import QtQuick.Controls 2.2 Window { visible: true width: 640 height: 480 title: qsTr("Hello World") ListView{ id: devicesView anchors.fill: parent.fill model: listModel delegate: Button{ text: (listModel.Name+listModel.type+listModel.address) //Binding { target: listModel; property: "labelText"; value: } } } }
Thanks in advance !!
-
1/1