πŸ’»
Programming Concept
  • πŸ‘¨β€πŸ”¬About Me
  • πŸ“—C++ STL Concept 2023
    • πŸ“–STL in CPP ( Part I)
    • πŸ“–STL in CPP ( Part II)
    • πŸ“–STL in CPP ( Part III )
    • πŸ“–STL in CPP ( Part IV )
    • πŸ“–STL in CPP ( Part V )
    • πŸ“–STL in CPP ( Part VI )
    • πŸ“–STL in CPP ( Part VII )
  • ✏️Pointers in C / C++
    • πŸ“–Pointers in details
  • πŸ“˜Strings in CPP 2023
  • πŸ•žThread in C++ 2023
  • πŸ““Smart Pointer in C++ 2023
  • Basic C++ Topics
    • πŸ’ΌType Casting in C++ 2023
  • πŸ’»Advanced C++ Programming
    • πŸŽ“Topics (Syllabus)
    • πŸ§‘β€πŸŽ“Inheritance and Polymorphism
    • πŸ–ŠοΈException Handling
    • πŸƒRuntime Type Information
    • πŸ“”An Overview of Templates
    • πŸ“‘Template in C++
  • πŸ’»Embedded Linux
    • πŸ–₯️Embedded Linux OS
      • Build Yocto Project Step By Step
      • How to install apt-get to the Yocto Project image
      • Installing gcc/g++ toolchain in yocto project
      • Installing GDB in yocto project
      • Installing ssh-server-dropbear for embedded linux in yocto project
      • Add Python To A Build
      • Add Boost To A Build
      • Adding Valgrind To Build
      • How To Add A Custom App To A Yocto Build
      • Raspberry Pi
    • πŸ“ΆCommunication Protocols
      • ✏️Working With I2C using c++
      • πŸ“”SPI Implementation with source code in C++
      • πŸ““Linux Serial Ports Using C/C++
      • πŸ–±οΈUART
      • πŸ–¨οΈUniversal GPIO Access
  • πŸ§‘β€πŸ’»QT QML
    • πŸ“˜QT QML Concept 2023
      • Why Qt Framework and QML
      • Sqlite3 for qtquick application
      • How To Install sqlite3 in windows 11 || Windows 10
      • Signals and Slots in Qt QML
      • Working with Signals and Slots in QML
      • Sorting QML ListModels
      • ListView In QML With Section Delegate
      • Registration of custom enum in QML
      • Registering a QML Type as a Singleton object
      • Using enumerations in QML without C ++
      • Registering a Singleton object to use β€œStatic” methods in QML
      • Connecting JavaScript files to other JavaScript files in a Qt / QML project
      • Positioning in Qt QML with anchors
      • TextInput validators in Qt Qml
      • Qt Qml Abstract Item Model using C++
      • Qt QML List Model
      • How to Register your C++ Class as a QML Type
      • Jabra Speaker Connect Qt Project
      • Qt | One article summarizing QObject
  • ▢️QT Concept
    • ℹ️Icon button
    • πŸ’»Register QML Singletone in CP
Powered by GitBook
On this page

Was this helpful?

  1. QT QML
  2. QT QML Concept 2023

Qt Qml Abstract Item Model using C++

PreviousTextInput validators in Qt QmlNextQt QML List Model

Last updated 1 year ago

Was this helpful?

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.

Subclassing

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

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

Let’s Look at the code :

personmodel.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

#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

#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

#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

#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

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

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

Let’s try to add one person :

After Adding Person Look Model Updated :

Since the model provides a more specialized interface than , it is not suitable for use with tree views; you will need to subclass 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 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 -based model that provides a list of strings to a widget. In such a case, we only need to implement the () function to return the number of items in the list, and the () function to retrieve items from the list.

Since the model represents a one-dimensional structure, the () function returns the total number of items in the model. The () function is implemented for interoperability with all kinds of views, but by default informs views that the model contains only one column.

When subclassing QAbstractListModel, you must provide implementations of the () and () functions. Well behaved models also provide a () implementation.

If your model is used within QML and requires roles other than the default ones provided by the () function, you must override it.

For editable list models, you must also provide an implementation of (), and implement the () function so that it returns a value containing .

Note that QAbstractListModel provides a default implementation of () 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 () and (). When implementing these functions, it is important to call the appropriate functions so that all connected views are aware of any changes:

An () implementation must call () before inserting new rows into the data structure, and it must call () immediately afterwards.

A () implementation must call () before the rows are removed from the data structure, and it must call () immediately afterwards.

main app after run

Note: You can find the whole source code on my .

πŸ§‘β€πŸ’»
πŸ“˜
QAbstractItemModel
QAbstractItemModel
QAbstractTableModel
QStringList
QListView
rowCount
data
rowCount
columnCount
rowCount
data
headerData
roleNames
setData
flags
Qt::ItemIsEditable
columnCount
insertRows
removeRows
insertRows
beginInsertRows
endInsertRows
removeRows
beginRemoveRows
endRemoveRows
github