Connect models to your QML user interface

Connect models from C++ backend to QML frontend

As shown from the previous tutorial, you can connect C++ code to QML by creating a class that will be treated as just another component in QML. However, you may want to represent more complicated data, such as data that needs to act as a custom ListModel or in some way needs to be delegated from a Repeater.

We can create our own models from the C++ side, and declare how the data from that model should be represented on the QML frontend.

Preparing the Class

In this tutorial, we will create a class that contains a QMap, where a QString is used as a key and QStringList objects are used as values. The frontend will be able to read and display the keys and values and be simple to use just like a one-dimensional array. It should look similar to a QML ListModel.

To do this, we need to declare a class that inherits from QAbstractListModel. Let's also add in some add data to the QMap. These declarations will be located in model.h.

Note

If you are following along, please remember to update your CMakeLists.txt file!

#pragma once

#include <QAbstractListModel>

class Model : public QAbstractListModel {
private:
    QMap<QString, QStringList> m_list = {
            {"Feline", {"Tigress",   "Waai Fuu"}},
            {"Fox",    {"Carmelita", "Diane", "Krystal"}},
            {"Goat",   {"Sybil",     "Toriel"}}
    };
};

Of course, we can't just display this class as is. We also need to tell QML on how to represent this data in the class. We can do this by overriding three virtual functions that are essential at doing this, all of which do their own tasks.

  • rowCount() - Think of this function as a way to tell QML how many items are in the model to represent.

  • roleNames() - You can think of role names as property names attached to data in QML. This function allows you to create those roles.

  • data() - This function is called when you want to retrieve the data that corresponds to the role names from the model.

Note

The custom role names created by roleNames() are only usable when a model is being delegated, and are not usable outside of it. See Models and Views.

Note

Technically, models in Qt are represented as tables, with rows and columns. So, what overriding rowCount() does is tell Qt how many rows are in a model. Since we are just dealing with a one-dimensional array in this tutorial, you can just think of "rows" as "number of elements."

Overriding and Implementing rowCount()

Let's override the function in the header file. The rowCount() comes with its own parameter, but will not be used in this example and is excluded.

class Model : public QAbstractListModel {
...
public:
    int rowCount(const QModelIndex &) const override;
};

Then, let's declare how many rows are in this model in model.cpp.

#include "model.h"

int Model::rowCount(const QModelIndex &) const {
    return m_list.count();
}

Overriding and Implementing roleNames()

Before we override roleNames(), we need to declare what the roles are in the C++ side using an public enum variable. The reason for this is because these values from the enum variable are passed into data() every time QML accesses a