Overview
I'm working on a project to learn how to implement C++ models in a QML project and I've ran into an issue that I can't quite figure out. I believe I've implemented the model correctly since I can manipulate it on the C++ side without issue, but I'm doing something wrong trying to expose it to the QML engine.
What I'm trying to do:
- Create the model in
main.cpp - Fill it with some data
- Call
setContextProperty()with the model on the engine's root context - In
main.qmlset up aGridViewcomponent using the C++ model
After doing the above, the project runs but nothing is displayed in the window. Then I tried to run main.qml using Qt Creator's tool QML Utility tool. Again, it runs but nothing is displayed. In the General Messages tab I get the message:
Starting external tool "/path/to/Qt/6.3.1/gcc_64/bin/qml /path/to/project/main.qml"
file:///path/to/project/main.qml:23: ReferenceError: cellModel is not defined
Some Context For The Curious
The project is to implement Conway's Game of Life as a simple proof of concept to prepare for a more complex future project. Behind the scenes, the C++ model CellModel uses class Environment which manages a 2D list of pointers to instances of class Cell which handle updating at timed intervals and holding the state values respectively.
Relevant Code
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "cellmodel.h"
int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
QGuiApplication app(argc, argv);
CellModel model = CellModel(nullptr);
model.resize(40, 40);
model.fillWithSoup();
QQmlApplicationEngine engine;
QQmlContext* context = engine.rootContext();
context->setContextProperty("cellModel", &model);
const QUrl url(QStringLiteral("qrc:/main.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
engine.load(url);
return app.exec();
}
cellmodel.h
#include <QAbstractItemModel>
#include <QDir>
#include <QHash>
#include <QByteArray>
class Environment;
class EnvironmentBuilder;
class CellModel : public QAbstractItemModel
{
Q_OBJECT
public:
enum Roles {
Living = Qt::UserRole + 1
};
Q_ENUM(Roles)
explicit CellModel(QObject *parent = nullptr);
Environment* environment() const {return m_environment;}
void setEnvironmefnt(Environment* environment);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role) const override;
bool setData(const QModelIndex &index, const QVariant &value,
int role = Qt::EditRole) override;
QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex& index) const override;
QHash<int, QByteArray> roleNames() const override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
signals:
void stateUpdated();
public slots:
Q_INVOKABLE void load(QString filename = "save.gol");
Q_INVOKABLE void save(QString filename = "save.gol");
Q_INVOKABLE void setSaveDirectory(QString directory = QDir::current().path());
Q_INVOKABLE void clearAll();
Q_INVOKABLE void fillWithSoup(qreal density = 0.4);
Q_INVOKABLE void nextStep();
Q_INVOKABLE void resize(int height = 1, int width = 1);
private:
EnvironmentBuilder* m_builder;
Environment* m_environment;
};
main.qml
import QtQuick 2.15
import QtQuick.Window 2.15
Window {
id: window
width: 640
height: 480
visible: true
title: qsTr("Hello World")
GridView {
property real cellScale: 10
implicitHeight: 400
implicitWidth: 400
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
cellHeight: cellScale
cellWidth: cellScale
model: cellModel
delegate: Rectangle {
border.width: 1
border.color: "black"
color: model.living ? "#cacaca" : "#424242"
}
}
}
What I've Tried
To check whether I made some error in subclassing QAbstractItemModel, I made a simpler model inheriting QAbstractListModel and tried using it instead only to face the same results. So the issue must lie in how I've tried exposing the model to the QML engine, but the setContextProperty() function seems so straightforward I fail to see how I could be misusing it.