c++qtqmlqabstractlistmodel

QAbstractListModel::Data() method is never called


I am trying to view a list of c++ models in qml by subclassing QAbstractListModel following this tutorial Models and Views: AbstractItemModel Example

Here is my implementation:

Item model class

class User
{
   private:
     QString m_macAddr;    
     QString m_firstName;    
     QString m_lastName;

 public:
     User();
     User(const QString &mac);
     QString macAddr() const;
     void setMacAddr(QString &mac);
  };
 User::User()
 {}
   User::User(const QString &mac){
     m_macAddr = mac;
  }     
  QString User::macAddr() const{
      return m_macAddr;
  }
  void User::setMacAddr(QString &mac){
      if(mac == m_macAddr)
          return;
       m_macAddr = mac;
  //    emit macAddrChanged();
  }

QAbstractListModel subclass

class UserListModel : public QAbstractListModel
{
    Q_OBJECT
public:
    // User model roles
    enum roles{
      macRole = Qt::UserRole + 1
    };
    UserListModel(QObject *parent = nullptr);
QModelIndex index(int row, int column,
                  const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &index) const override;
QModelIndex getIndex(int r, int c, void *p);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
    void addUser(const User &user); 
private:
    QList<User> m_users;
protected:
    QHash<int, QByteArray> rolesNames() const;
};
// Class inplementation.

UserListModel::UserListModel(QObject *parent)
: QAbstractListModel(parent)
{

}

void UserListModel::addUser(const User &user){
    beginInsertRows(QModelIndex(), rowCount(), rowCount());
    m_users << user;
    endInsertRows();
}

int UserListModel::rowCount(const QModelIndex &parent) const
{
    return m_users.count();
}

QVariant UserListModel::data(const QModelIndex &index, int role) const
{
    if (index.row() < 0 || index.row() >= rowCount())
        return QVariant();
    const User &user = m_users[index.row()];
        if(role == macRole){
            return user.macAddr();
        }
        return QVariant();
    }    
QModelIndex UserListModel::index(int row, int column, const QModelIndex &parent) const
{
    return parent;
}

QModelIndex UserListModel::parent(const QModelIndex &index) const
{
    return index;
}

QModelIndex UserListModel::getIndex(int r, int c, void *p) {
    return this->createIndex(r, c, p);
}
QHash<int, QByteArray> UserListModel::rolesNames() const {
    QHash<int, QByteArray> roles;
    roles[macRole] = "mac";
    return roles;
}

main.cpp

QQmlApplicationEngine engine;
QString mac = "12:3e:3w:4r:33";
userlistModel->addUser(User(mac));
userlistModel->addUser(User(mac));
userlistModel->addUser(User(mac));
userlistModel->addUser(User(mac));
engine.rootContext()->setContextProperty("usersModel", userlistModel);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
QModelIndex id = userlistModel->getIndex(1, 0, 0);

QVariant v1 = userlistModel->data(id, Qt::UserRole + 1);

qDebug() << "===========" << v1.toString();
controller::DatabaseService<SqliteDB> *sqliteDb = new controller::DatabaseService<SqliteDB>();
if (engine.rootObjects().isEmpty())
    return -1;
return app.exec();

QML

    ListView{
        id: listView
        anchors.fill: parent
        model:usersModel
        delegate:  Component { HorizontalListItem{mac: mac}}
    }

The Problem is :

In main function I am adding 4 models to the list model but, They are shown in qml without data. althought, I am trying to view mac role.


what I tried


Solution

  • It is not necessary that you override the index, or parent methods, nor do you create the getIndex method. In your case you need to implement the roleNames method:

    main.cpp

    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include <QQmlContext>
    #include <QAbstractListModel>
    #include <QDebug>
    
    class User
    {
        QString m_macAddr;
    public:
        User(){}
        User(const QString &mac): m_macAddr(mac){}
        QString macAddr() const{return m_macAddr;}
        void setMacAddr(QString &mac){m_macAddr = mac;}
    };
    
    class UserListModel : public QAbstractListModel
    {
    public:
        enum roles{
            macRole = Qt::UserRole + 1
        };
        explicit UserListModel(QObject *parent = nullptr)
            : QAbstractListModel(parent){}
        int rowCount(const QModelIndex &parent = QModelIndex()) const override {
            if (parent.isValid())
                return 0;
            return m_users.count();
        }
        QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override {
            if (!index.isValid())
                return QVariant();
            if (index.row() < 0 || index.row() >= rowCount())
                return QVariant();
            const User &user = m_users[index.row()];
            if(role == macRole)
                return user.macAddr();
            return QVariant();
        }
        QHash<int, QByteArray> roleNames() const override{
            QHash<int, QByteArray> roles;
            roles[macRole] = "mac";
            return roles;
        }
        void addUser(const User &user){
            beginInsertRows(QModelIndex(), rowCount(), rowCount());
            m_users << user;
            endInsertRows();
        }
    private:
        QList<User> m_users;
    };
    
    
    int main(int argc, char *argv[])
    {
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    
        QGuiApplication app(argc, argv);
    
        QQmlApplicationEngine engine;
        UserListModel userlistModel;
        QString mac = "12:3e:3w:4r:33";
        userlistModel.addUser(User(mac));
        userlistModel.addUser(User(mac));
        userlistModel.addUser(User(mac));
        userlistModel.addUser(User(mac));
        QModelIndex ix = userlistModel.index(1, 0);
        QVariant v = userlistModel.data(ix, UserListModel::macRole);
        qDebug() << "===========" << v.toString();
        engine.rootContext()->setContextProperty("usersModel", &userlistModel);
        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
    
    Window {
        visible: true
        width: 640
        height: 480
        title: qsTr("Hello World")
    
        ListView{
            anchors.fill: parent
            model:usersModel
            delegate: Component
            {
                Text{
                    text:  model.mac
                }
            }
        }
    }