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. QAbstractListModel example with MVVM pattern
Forum Updated to NodeBB v4.3 + New Features

QAbstractListModel example with MVVM pattern

Scheduled Pinned Locked Moved Solved QML and Qt Quick
qmlc++mvvm
1 Posts 1 Posters 493 Views 1 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.
  • A Offline
    A Offline
    AROH
    wrote on 7 Mar 2023, 10:43 last edited by AROH 3 Jul 2023, 10:49
    #1

    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 Reply Last reply
    0
    • A AROH has marked this topic as solved on 8 Mar 2023, 14:02

    1/1

    7 Mar 2023, 10:43

    • Login

    • Login or register to search.
    1 out of 1
    • First post
      1/1
      Last post
    0
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Get Qt Extensions
    • Unsolved