Using C++ Models with Qt Quick Views example
-
I'm trying to adapt this example to my needs. Here my code:
modelcontent.h
#ifndef MODELCONTENT_H #define MODELCONTENT_H #include <QObject> #include <QAbstractListModel> class Content { public: Content(const QString &label) : _label(label) { } QString label() const { return _label; } private: QString _label; }; class ModelContent : public QAbstractListModel { Q_OBJECT public: enum ContentRoles { LabelRole = Qt::UserRole + 1, }; explicit ModelContent(QObject *parent = nullptr) : QAbstractListModel(parent) { } void addContent(const Content &content) { beginInsertRows(QModelIndex(), rowCount(), rowCount()); _content << content; endInsertRows(); } int rowCount(const QModelIndex &parent = QModelIndex()) const { Q_UNUSED(parent); return _content.size(); } QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const { if (index.row() < 0 || index.row() >= _content.size()) return QVariant(); const Content &content = _content[index.row()]; switch (role) { case LabelRole: return content.label(); default: return QVariant(); } } private: QList<Content> _content; protected: QHash<int, QByteArray> roleNames() const { QHash<int, QByteArray> roles; roles[LabelRole] = "label"; return roles; } }; #endif // MODELCONTENT_H
flow.h
#ifndef FLOW_H #define FLOW_H #include <QObject> #include "modelcontent.h" class Flow : public QObject { Q_OBJECT public: explicit Flow(QObject *parent = nullptr); ModelContent modelContent; }; #endif // FLOW_H
flow.cpp*
#include "flow.h" Flow::Flow(QObject *parent) : QObject(parent) { modelContent.addContent(Content("abc")); modelContent.addContent(Content("def")); }
main.cpp
#include <QGuiApplication> #include <QQmlApplicationEngine> #include <QQmlContext> #include "flow.h" int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); Flow flow; QQmlApplicationEngine engine; 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.setInitialProperties({{"model", QVariant::fromValue(&flow.modelContent)}}); engine.load(url); return app.exec(); }
main.qml
import QtQuick import QtQuick.Controls ApplicationWindow { id: window width: 1920 height: 1080 visible: true visibility: "FullScreen" color: "black" Component { id: delegate Item { id: item width: 864*0.7; height: 1536*0.7 Text { required property string label anchors.centerIn: parent text: label } } } PathView { id: view anchors.fill: parent anchors.bottomMargin: 150 anchors.topMargin: 50 pathItemCount: 3 preferredHighlightBegin: 0.5 preferredHighlightEnd: 0.5 highlightRangeMode: PathView.StrictlyEnforceRange highlightMoveDuration: 1000 snapMode: PathView.SnapToItem rotation: -90 required model delegate: delegate path: Path { startX: 0; startY: view.height / 2 PathLine {x: view.width/2; y: view.height / 2; } PathLine {x: view.width; y: view.height / 2; } } } }
No errors during building, but at run-time I get:
QML debugging is enabled. Only use this in a safe environment.
QQmlApplicationEngine failed to create component
qrc:/main.qml: Setting initial properties failed: ApplicationWindow does not have a property called model
qrc:/main.qml:117:5: Required property model was not initialized
12:06:36: Remote process crashed.Line 117 is:
PathView {
I double checked the example and I didn't find anything I missed.
I just changed thesetInitialProperties
call fromQQuickView
toQQmlApplicationEngine
.Any idea?
-
@Mark81 said in Using C++ Models with Qt Quick Views example:
I think you will have many name clashes:
engine.setInitialProperties({{"model", QVariant::fromValue(&flow.modelContent)}});
==>model
is a common property name for many classes, to avoid to use it a global property name!- same with component called
delegate
, this is a very bad idea ==>delegate: delegate
will connectdelegate
to itself!
first cleanup you class/component/variable naming to avoid those clashes.
-
You should tell this to the Qt developers :-) I found this name in the linked example.
Anyway, I changed:engine.setInitialProperties({{"modelContent", QVariant::fromValue(&flow.modelContent)}}); ... required modelContent delegate: delegateContent
Now the errors are these:
QQmlApplicationEngine failed to create component
qrc:/main.qml: Property modelContent was marked as required but does not exist
QQmlComponent: Component destroyed while completion pending
This may have been caused by one of the following errors:
qrc:/main.qml: Property modelContent was marked as required but does not exist -
The example you linked work because it was assigning to the existing
model
property or theListView
.Here you would need to define a property to hold your model in the root object of your QML, the
ApplicationWindow
in your case:ApplicationWindow { id: window required property QtObject model // ... PathView { model: window.model // ... } }
or :
ApplicationWindow { property alias model: view.model // ... PathView { id: view // ... } }
-
@GrecKo Thanks, I understood
ListView
,GridView
,PathView
and so on differ for how they show the items only.
The first syntax worked, at least a bit more.Now I have to understand how to declare the required property
label
.
The example used this syntax:delegate: Text { required property string type required property string size text: "Animal: " + type + ", " + size }
but it doesn't work for me:
Required property label was not initialized
I'm very sorry but I don't understand this syntax yet. I'll be very glad if you can help me to make this to work but also if there is a page in the docs that explain how to achieve this simple task.