Is there a way to make QML use 2D data model ?
-
Hi,
Are you looking for something like described in the QAbstractItemModel Subclass in the
Using C++ Models with Qt Quick Viewschapter of Qt's documentation ? -
Hi,
Are you looking for something like described in the QAbstractItemModel Subclass in the
Using C++ Models with Qt Quick Viewschapter of Qt's documentation ? -
I'm trying to use QRangeModel as it seems to be a very neat feature.
I start a new QML Project, add a C++ class to it, instance my class on the main.cpp main() to create my data, create a QRangeModel using the data, add a property with that QRangeModel, that I finally use as model on my QML file.
For the moment I can only see on the QML side the QRangeModel as a QQmlListModel (from console.log on Component.onCompleted), but I don't see how to use its data.
Here's my code :
main.cpp#include <QGuiApplication> #include "piece.h" #include <QRangeModel> #include <QQmlApplicationEngine> #include <QVariant> int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QList<Piece> mesPieces; mesPieces.append(Piece(20, 20)); mesPieces.append(Piece(60, 0)); QRangeModel modele(&mesPieces); QQmlApplicationEngine engine; engine.setInitialProperties({ {"monModele", QVariant::fromValue(&modele)} }); QObject::connect( &engine, &QQmlApplicationEngine::objectCreationFailed, &app, []() { QCoreApplication::exit(-1); }, Qt::QueuedConnection); engine.loadFromModule("testDeleg2", "Main"); return QGuiApplication::exec(); }piece.h (class header)
#ifndef PIECE_H #define PIECE_H #include <QtTypes> class Piece { public: qreal x, y; Piece() {}; Piece(qreal px, qreal py) : x(px), y(py) {} void setX(const qreal newX) {m_x = newX;} void setY(const qreal newY) {m_y = newY;} private: qreal m_x; qreal m_y; }; #endif // PIECE_HQML
import QtQuick import QtQuick.Controls.Basic import QtQuick.Shapes ApplicationWindow { id: window width: 640 height: 480 minimumWidth: 200 minimumHeight: 250 visible: true title: qsTr("test QRangeModel") /*ListModel { id: monModele ListElement { x: 20 ; y: 20 } ListElement { x: 60 ; y: 0 } }*/ required property AbstractItemModel monModele Repeater { model : monModele Shape { anchors.fill: parent ShapePath { strokeColor: "yellow" fillColor: "yellow" strokeWidth: 1 startX: model.x startY: model.y PathLine { relativeX: 0; relativeY: 50 } PathLine { relativeX: 50; relativeY: 0 } } } Component.onCompleted: { console.log(monModele); } } }The ListModels contains what the QRangeModel is supposed to have.
Maybe do I need to add getters ? -
I haven't used it in such a fashion yet but I think what you want is in the Structs and gadgets as rows chapter In QRangeModel's documentation.
-
I changed my class, so now it's a Q_GADGET, having properties with getters (READ x and READ y), but even with Q_INVOKABLE, I can't use any of them on the QML side. When I run on debug with a breakpoint and inspect the QRangeModel, it does not seem to have the values, no children. I'm certainly missing something.
-
To get my model data from QML, i needed to use data, giving it an index by using its index function and the Qt.DisplayRole.
startX: monModele.data(monModele.index(index,0), Qt.DisplayRole) startY: monModele.data(monModele.index(index,1), Qt.DisplayRole)Now I'm adding the 2d data part.
-
You should follow the following section to expose your properties as roles:
https://doc.qt.io/qt-6/qrangemodel.html#gadgets-and-objects-as-multi-role-itemsYou should then be able to write
startY: model.y(with arequired property QtObject modelin the delegate) -
You should follow the following section to expose your properties as roles:
https://doc.qt.io/qt-6/qrangemodel.html#gadgets-and-objects-as-multi-role-itemsYou should then be able to write
startY: model.y(with arequired property QtObject modelin the delegate)@GrecKo Thank you, I am using a Q_GADGET class but was missing the required property in the delegate for each property. Sadly adding the required property in the repeater is not enough. I tried to put it directly into the repeater after the model setting, there it is not initialized and get undefined as value.
My gadget class is as basic as possible, but I'm not able to set it up correctly to be able to use properties name on the QML side. For the moment I'm sticking to the mymodel.data(...index(...), Qt.DisplayRole) that works.
-
Can you share a minimal compilable application with your current code ?
That would allow us to check what is going on. -
the data class
#ifndef PIECE_H #define PIECE_H #include <QtCore/qobjectdefs.h> #include <QtCore/qtmetamacros.h> class piece { Q_GADGET Q_PROPERTY(float x READ x WRITE setX) Q_PROPERTY(float y READ y WRITE setY) public: piece() : m_x(0.0f), m_y(0.0f) {} piece(const piece &) = default; piece(piece &&) = default; piece &operator=(const piece &) = default; piece &operator=(piece &&) = default; explicit piece(const float &x, const float &y) : m_x(x), m_y(y) {} void setX(float newX) { if (!qFuzzyCompare(newX, m_x)) m_x = newX; } void setY(float newY) { if (!qFuzzyCompare(newY, m_y)) m_y = newY; } private: float m_x; float m_y; float x() const { return m_x; } float y() const { return m_y; } }; #endif // PIECE_Hmain.cpp
#include "piece.h" #include <QRangeModel> #include <QGuiApplication> #include <QQmlApplicationEngine> int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QList<piece> mesPieces; mesPieces.append(piece(20.0f, 20.0f)); mesPieces.append(piece(60.0f, 0.0f)); mesPieces.append(piece(100.0f, 30.0f)); QRangeModel modele(&mesPieces); QQmlApplicationEngine engine; engine.setInitialProperties({{"monModele", QVariant::fromValue(&modele) }}); QObject::connect( &engine, &QQmlApplicationEngine::objectCreationFailed, &app, []() { QCoreApplication::exit(-1); }, Qt::QueuedConnection); engine.loadFromModule("testQRange1", "Main"); return QGuiApplication::exec(); }main.qml
import QtQuick import QtQuick.Controls.Basic import QtQuick.Shapes ApplicationWindow { id: window width: 640 height: 480 visible: true title: qsTr("test QRangeModel") required property AbstractItemModel monModele Repeater { model : monModele Shape { property real mx : monModele.data(monModele.index(index, 0), Qt.DisplayRole) property real my : monModele.data(monModele.index(index, 1), Qt.DisplayRole) anchors.fill: parent ShapePath { strokeColor: "yellow" fillColor: "yellow" strokeWidth: 1 startX: mx startY: my PathLine { relativeX: 0; relativeY: 50 } PathLine { relativeX: 50; relativeY: 0 } } } } }It doesn't work if I try to replace mx and my properties by required property real x (and y)