> For the complete documentation index, see [llms.txt](https://adeshsingh.gitbook.io/programming/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://adeshsingh.gitbook.io/programming/qt-qml/qt-qml-concept-2023/qt-qml-abstract-item-model-using-c++.md).

# Qt Qml Abstract Item Model using C++

<figure><img src="/files/UWiTIHdXpuiMilWlDFFW" alt=""><figcaption></figcaption></figure>

The `QAbstractListModel` class provides an abstract model that can be subclassed to create one-dimensional list models .

### Detailed Description

QAbstractListModel provides a standard interface for models that represent their data as a simple non-hierarchical sequence of items. It is not used directly, but must be subclassed.

Since the model provides a more specialized interface than [QAbstractItemModel](https://doc.qt.io/qt-5/qabstractitemmodel.html), it is not suitable for use with tree views; you will need to subclass [QAbstractItemModel](https://doc.qt.io/qt-5/qabstractitemmodel.html) if you want to provide a model for that purpose. If you need to use a number of list models to manage data, it may be more appropriate to subclass [QAbstractTableModel](https://doc.qt.io/qt-5/qabstracttablemodel.html) instead.

Simple models can be created by subclassing this class and implementing the minimum number of required functions. For example, we could implement a simple read-only [QStringList](https://doc.qt.io/qt-5/qstringlist.html)-based model that provides a list of strings to a [QListView](https://doc.qt.io/qt-5/qlistview.html) widget. In such a case, we only need to implement the [rowCount](https://doc.qt.io/qt-5/qabstractitemmodel.html#rowCount)() function to return the number of items in the list, and the [data](https://doc.qt.io/qt-5/qabstractitemmodel.html#data)() function to retrieve items from the list.

Since the model represents a one-dimensional structure, the [rowCount](https://doc.qt.io/qt-5/qabstractitemmodel.html#rowCount)() function returns the total number of items in the model. The [columnCount](https://doc.qt.io/qt-5/qabstractitemmodel.html#columnCount)() function is implemented for interoperability with all kinds of views, but by default informs views that the model contains only one column.

#### Subclassing

When subclassing QAbstractListModel, you must provide implementations of the [rowCount](https://doc.qt.io/qt-5/qabstractitemmodel.html#rowCount)() and [data](https://doc.qt.io/qt-5/qabstractitemmodel.html#data)() functions. Well behaved models also provide a [headerData](https://doc.qt.io/qt-5/qabstractitemmodel.html#headerData)() implementation.

If your model is used within QML and requires roles other than the default ones provided by the [roleNames](https://doc.qt.io/qt-5/qabstractitemmodel.html#roleNames)() function, you must override it.

For editable list models, you must also provide an implementation of [setData](https://doc.qt.io/qt-5/qabstractitemmodel.html#setData)(), and implement the [flags](https://doc.qt.io/qt-5/qabstractlistmodel.html#flags)() function so that it returns a value containing [Qt::ItemIsEditable](https://doc.qt.io/qt-5/qt.html#ItemFlag-enum).

Note that QAbstractListModel provides a default implementation of [columnCount](https://doc.qt.io/qt-5/qabstractitemmodel.html#columnCount)() that informs views that there is only a single column of items in this model.

Models that provide interfaces to resizable list-like data structures can provide implementations of [insertRows](https://doc.qt.io/qt-5/qabstractitemmodel.html#insertRows)() and [removeRows](https://doc.qt.io/qt-5/qabstractitemmodel.html#removeRows)(). When implementing these functions, it is important to call the appropriate functions so that all connected views are aware of any changes:

* An [insertRows](https://doc.qt.io/qt-5/qabstractitemmodel.html#insertRows)() implementation must call [beginInsertRows](https://doc.qt.io/qt-5/qabstractitemmodel.html#beginInsertRows)() *before* inserting new rows into the data structure, and it must call [endInsertRows](https://doc.qt.io/qt-5/qabstractitemmodel.html#endInsertRows)() *immediately afterwards*.
* A [removeRows](https://doc.qt.io/qt-5/qabstractitemmodel.html#removeRows)() implementation must call [beginRemoveRows](https://doc.qt.io/qt-5/qabstractitemmodel.html#beginRemoveRows)() *before* the rows are removed from the data structure, and it must call [endRemoveRows](https://doc.qt.io/qt-5/qabstractitemmodel.html#endRemoveRows)() *immediately afterwards*.

So Let’s Create a class which is abstract from QAbstractListModel.

```cpp
PersonModel::PersonModel(QObject *parent) : QAbstractListModel(parent)
```

Let’s Look at the code :

personmodel.cpp

```cpp
#include <QDebug>
#include "personmodel.h"
#include "person.h"
PersonModel::PersonModel(QObject *parent) : QAbstractListModel(parent)
{
    addPerson(new Person("Aksh Singh","red",33));
    addPerson(new Person("Laksh Kumar","cyan",26));
    addPerson(new Person("Luccky The Raccer","yellow",44));

}

int PersonModel::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent)
    return mPersons.size();
}

QVariant PersonModel::data(const QModelIndex &index, int role) const
{
    if (index.row() < 0 || index.row() >= mPersons.count())
        return QVariant();
    //The index is valid
    Person * person = mPersons[index.row()];
    if( role == NamesRole)
        return person->names();
    if( role == FavoriteColorRole)
        return person->favoriteColor();
    if( role == AgeRole)
        return person->age();
     return QVariant();
}

bool PersonModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    Person * person = mPersons[index.row()];
    bool somethingChanged = false;

    switch (role) {
    case NamesRole:
    {
        if( person->names()!= value.toString()){
            qDebug() << "Changing names for " << person->names();
            person->setNames(value.toString());
            somethingChanged = true;
        }
    }
        break;
    case FavoriteColorRole:
    {
        if( person->favoriteColor()!= value.toString()){
            qDebug() << "Changing color for " << person->names();
            person->setFavoriteColor(value.toString());
            somethingChanged = true;
        }
    }
        break;
    case AgeRole:
    {
        if( person->age()!= value.toInt()){
            qDebug() << "Changing age for " << person->names();
            person->setAge(value.toInt());
            somethingChanged = true;
        }
    }

    }

    if( somethingChanged){
        emit dataChanged(index,index,QVector<int>() << role);
        return true;
    }
    return false;
}

Qt::ItemFlags PersonModel::flags(const QModelIndex &index) const
{
    if (!index.isValid())
        return Qt::NoItemFlags;
    return Qt::ItemIsEditable;
}

QHash<int, QByteArray> PersonModel::roleNames() const
{
    QHash<int, QByteArray> roles;
    roles[NamesRole] = "names";
    roles[FavoriteColorRole] = "favoriteColor";
    roles[AgeRole] = "age";
    return roles;
}

void PersonModel::addPerson(Person *person)
{
    const int index = mPersons.size();
    beginInsertRows(QModelIndex(),index,index);
    mPersons.append(person);
    endInsertRows();
}

void PersonModel::addPerson()
{
    Person *person = new Person("Added Person","yellowgreen",45,this);
    addPerson(person);
}

void PersonModel::addPerson(const QString &names, const int &age)
{
    Person *person=new Person(names,"yellowgreen",age);
    addPerson(person);
}

void PersonModel::removePerson(int index)
{
    beginRemoveRows(QModelIndex(), index, index);
    mPersons.removeAt(index);
    endRemoveRows();
}

void PersonModel::removeLastPerson()
{
    removePerson(mPersons.size()-1);
}
```

personmodel.h

```cpp
#ifndef PERSONMODEL_H
#define PERSONMODEL_H

#include <QAbstractListModel>
#include <QObject>
#include "person.h"

class PersonModel : public QAbstractListModel
{
    Q_OBJECT
    enum PersonRoles{
        NamesRole = Qt::UserRole + 1,
        FavoriteColorRole,
        AgeRole
    };
public:
    explicit PersonModel(QObject *parent = nullptr);

    int rowCount(const QModelIndex &parent = QModelIndex()) const;

    QVariant data(const QModelIndex &index, int role) const;

    bool setData(const QModelIndex &index, const QVariant &value, int role);

    Qt::ItemFlags flags(const QModelIndex& index) const;

    QHash<int, QByteArray> roleNames() const;

    void addPerson( Person *person);
    Q_INVOKABLE void addPerson();
    Q_INVOKABLE void addPerson(const QString & names,const int & age);
    Q_INVOKABLE void removePerson(int index);
    Q_INVOKABLE void removeLastPerson();

signals:

public slots:
private :
    QList<Person*> mPersons;
};

#endif // PERSONMODEL_H
```

person.h

```cpp
#ifndef PERSON_H
#define PERSON_H

#include <QObject>

class Person : public QObject
{
    Q_OBJECT
public:
    explicit Person(QString names,QString favoriteColor,int age,QObject *parent = nullptr);

    Q_PROPERTY(int age READ age WRITE setAge NOTIFY ageChanged)
    Q_PROPERTY(QString favoriteColor READ favoriteColor WRITE setFavoriteColor NOTIFY favoriteColorChanged)
    Q_PROPERTY(QString names READ names WRITE setNames NOTIFY namesChanged)
    int age() const;
    void setAge(int newAge);

    const QString &favoriteColor() const;
    void setFavoriteColor(const QString &newFavoriteColor);

    const QString &names() const;
    void setNames(const QString &newNames);

public slots:
signals:

    void ageChanged();
    void favoriteColorChanged();

    void namesChanged();

private:
    int m_age;
    QString m_favoriteColor;
    QString m_names;
};

#endif // PERSON_H
```

person.cpp

```cpp
#include "person.h"

Person::Person(QString names,QString favoriteColor,int age,QObject *parent)
    : QObject{parent}
    ,m_age{age}
    ,m_favoriteColor{favoriteColor}
    ,m_names{names}

{

}

int Person::age() const
{
    return m_age;
}

void Person::setAge(int newAge)
{
    if (m_age == newAge)
        return;
    m_age = newAge;
    emit ageChanged();
}

const QString &Person::favoriteColor() const
{
    return m_favoriteColor;
}

void Person::setFavoriteColor(const QString &newFavoriteColor)
{
    if (m_favoriteColor == newFavoriteColor)
        return;
    m_favoriteColor = newFavoriteColor;
    emit favoriteColorChanged();
}

const QString &Person::names() const
{
    return m_names;
}

void Person::setNames(const QString &newNames)
{
    if (m_names == newNames)
        return;
    m_names = newNames;
    emit namesChanged();
}
```

Let’s register model into main.cpp

```cpp
#include <QGuiApplication>
#include <QQmlContext>
#include <QQmlApplicationEngine>
#include "personmodel.h"


int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    PersonModel mModel;

    QQmlApplicationEngine engine;

     engine.rootContext()->setContextProperty("myModel",&mModel);

    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}
```

Create Input Dialog called InputDialog.qml

```qml
import QtQuick 2.12
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.12
import QtQuick.Controls.Imagine 2.3
Item {
    id : rootId
    function openDialog(){
        inputDialog.open()
    }

    property alias personNames : addPerNamesField.text
    property alias personAge: addPerAgeField.value
    signal inputDialogAccepted()

    Dialog {
        id: inputDialog

        x: (parent.width - width) / 2
        y: (parent.height - height) / 2

        width: parent.width/2 //Breaks the binding loop introduced in Qt 5.12.
        parent: Overlay.overlay

        focus: true
        modal: true
        title: "Person data"
        standardButtons: Dialog.Ok | Dialog.Cancel

        ColumnLayout {
            spacing: 20
            anchors.fill: parent
            Label {
                elide: Label.ElideRight
                text: "Please enter the data:"
                Layout.fillWidth: true
            }
            TextField {
                id : addPerNamesField
                focus: true
                placeholderText: "Names"
                Layout.fillWidth: true
            }
            SpinBox {
                editable: true
                id : addPerAgeField
                value : 13
                Layout.fillWidth: true
            }

        }

        onAccepted: {
            console.log("Accepted adding person")
            rootId.inputDialogAccepted()

        }
        onRejected: {
            console.log("Rejected adding person")
        }
    }
}
```

Final Code main.qml

```qml
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.12
import QtQuick.Dialogs
import QtQuick.Controls.Imagine 2.3

/* Here you need to follow the instruction 
For Qt5.15.x --> import QtQuick.Dialogs 1.3
For Qt6.x.x -->  import QtQuick.Dialogs 
Note : I am using Qt6.3.x so i imported --> import QtQuick.Dialogs 
*/
ApplicationWindow {
    visible: true
    width: 400
    height: 600
    minimumWidth: 400
    minimumHeight: 600
    title:  qsTr("blogs.thearticleof.com")
    Label{
        text: qsTr("blogs.thearticleof.com")
        font.pixelSize: 34
        color: "grey"
        opacity: 0.5
        rotation: 360-75
        anchors.centerIn: parent
        anchors.topMargin: 200
    }

    ColumnLayout{
        anchors.fill: parent
        anchors.topMargin: 10
        ListView{
            id : mListView
            Layout.fillWidth: true
            Layout.fillHeight: true

            model : myModel
            delegate:RowLayout{
                width: parent.width
                spacing: 10
                Layout.margins: 10
                TextField{
                    text : names
                    Layout.fillWidth: true
                    Layout.leftMargin: 10
                    onEditingFinished: {
                        console.log("Editing finished, new text is :"+ text + " at index :" + index)
                        model.names = text //The roles here are defined in model class

                    }
                }

                SpinBox{
                    id : mSpinbox
                    editable: true
                    Layout.fillWidth: true
                    onValueChanged: {
                        model.age = value;
                    }
                    Component.onCompleted: {
                        mSpinbox.value = model.age
                    }
                }
                Rectangle{
                    width : 30
                    height: 30
                    radius: width/2
                    color: model.favoriteColor
                    Layout.rightMargin: 10
                    MouseArea{
                        anchors.fill: parent
                        ColorDialog{
                            id: colorDialog
                            title: "Please choose a color"
                            onAccepted: {
                                console.log("You choose: " + colorDialog.color)
                                model.favoriteColor = colorDialog.color
                            }
                            onRejected: {
                                console.log("Canceled")

                            }
                        }
                        onClicked: {
                            colorDialog.open()

                        }
                    }
                }
            }
        }

        RowLayout{
            width : parent.width

            Button{
                Layout.fillWidth: true
                height: 50
                text : "Add Person";
                highlighted: true
                onClicked: {
                    input.openDialog()
                }
                InputDialog{
                    id : input
                    onInputDialogAccepted: {
                        console.log("Here in main, dialog accepted");
                        console.log( " names : " + personNames + " age :" + personAge)
                        myModel.addPerson(personNames,personAge)
                    }
                }


            }
            Button{
                Layout.fillWidth: true
                height: 50
                highlighted: true
                text : "Remove Last";
                onClicked: {
                    myModel.removeLastPerson()
                }
            }
        }
    }

}
```

Let’s try build and run the project

<figure><img src="https://blogs.thearticleof.com/wp-content/uploads/2022/11/CppModel1-1024x537.png" alt="" height="537" width="1024"><figcaption><p>main app after run</p></figcaption></figure>

Let’s try to add one person :

<figure><img src="https://blogs.thearticleof.com/wp-content/uploads/2022/11/cppmodel2-1024x538.png" alt="" height="538" width="1024"><figcaption></figcaption></figure>

After Adding Person Look Model Updated :

<figure><img src="https://blogs.thearticleof.com/wp-content/uploads/2022/11/cppmodel3-1024x535.png" alt="" height="535" width="1024"><figcaption></figcaption></figure>

Note: You can find the whole source code on my [github](https://github.com/cppqtdev/How-to-Register-your-C-Class-as-a-QML-Type).
