Reputation: 173
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:
main.cpp
setContextProperty()
with the model on the engine's root contextmain.qml
set up a GridView
component using the C++ modelAfter 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.
Upvotes: 2
Views: 312
Reputation: 173
It turns out that I misunderstood my issue! As @Amfasis pointed out, a TableView
component would be more appropriate for my application. I changed the GridView
component accordingly and everything works. I was exposing the model to QML correctly the whole time.
Also of note: In my question text I mentioned that I ran main.qml
in the QML Utility tool and got a ReferenceError. However, I've realized that the QML Utility tool would always read the file without my model being in the QML context since I exposed it in main.cpp
which the tool doesn't read.
Upvotes: 2