<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Is there a way to make QML use 2D data model ?]]></title><description><![CDATA[<p dir="auto">Hello, I'm currently using QML and C++ for an application that uses QtQuick3D and it's going really nicely. My problem is that I need to feed QML with data containing a field with more than one row and it doesn't work. I'm using a workaround by putting those rows into a string and using component.onCompleted on the QML side to unflatten the data and dynamically create the list model. But i'm wondering whether there is a way to use another class than QAbstractListModel that handles data fields having more than one value, maybe QAbstractTableModel ? But I'm afraid that there's no datamodel object that I can use for my needs (creating a composite shape, having a parent polygon that can be moved/rotated and children lines that can be hovered/clicked). Is there a demo application using QAbtractTableModel or something alike ? I read somewhere that 2D data model is one of the weaknesses of Qt/QML, so I'm not expecting that it's possible.</p>
<p dir="auto">here's my code (QML) : "nested" datamodels gets a string and unflat them using js function creeLignes() from their Component.onCompleted</p>
<pre><code>                    Repeater { // UNE PIECE COMPLETE
                        model: pieces
                        delegate : Shape {
                            containsMode: Shape.FillContains
                            DragHandler {cursorShape: Qt.ClosedHandCursor}
                            ShapePath { // POLYGONE FORMANT LA PIECE
                                fillRule: ShapePath.WindingFill
                                fillColor: iToC[coul]
                                strokeWidth: -1
                                PathSvg { path: contour }
                            }

                            property real tmpPosX : posX
                            property real tmpPosY : posY
                            property real tmpAngle : angle

                            x: tmpPosX
                            y: tmpPosY
                            rotation: tmpAngle

                            onXChanged: {
                                pieces.setPosX(index, x);
                            }
                            onYChanged: {
                                pieces.setPosY(index, y);
                            }
                            onRotationChanged: {
                                pieces.setAngle(index, rotation);
                            }

                            Text { // NUMERO DE LA PIECE (aka n° de sa première facette)
                                font.pointSize: 10
                                color: "black"
                                text: num
                                horizontalAlignment: Qt.AlignHCenter
                                verticalAlignment: Qt.AlignVCenter
                                x: centre.x - (contentWidth /2)
                                y: centre.y - (contentHeight /2)
                            }
                            Repeater { // CHAQUE NUMERO D'ARETE (ENTRE 2 FACETTES)
                                model: ListModel {}
                                Text {
                                    text: model.txt
                                    font.pointSize: 6
                                    horizontalAlignment: Qt.AlignHCenter
                                    verticalAlignment: Qt.AlignVCenter
                                    color: "#1500ff"
                                    transform: [
                                        Translate { x: 0; y: -7 },
                                        Rotation { angle: 180+model.a },
                                        Translate { x: model.x; y: model.y }
                                    ]
                                }
                                Component.onCompleted: {
                                    this.model.clear();
                                    var txt = nTxt.split(';');
                                    txt = txt.filter(el=&gt;el);
                                    for (var i in txt) {
                                        var el = txt[i].split(",").map(Number);
                                        this.model.append({"txt": el[0], "x": el[1], "y": el[2], "a": el[3]});
                                    }
                                }
                            }

                            function creeLignes (lignes, liste) {
                                liste.clear();
                                const d = 0.25;
                                var lpli = lignes.split(";");
                                lpli= lpli.filter((el) =&gt; el);
                                for (var i in lpli) {
                                    var p = lpli[i].split(" ");
                                    p = p.map(Number);
                                    var x1 = p[0];
                                    var y1 = p[1];
                                    var x2 = p[2];
                                    var y2 = p[3];
                                    var f1 = p[4];
                                    var f2 = p[5];
                                    if (x1 &gt; x2) {
                                        [x2, x1] = [x1, x2];
                                        [y2, y1] = [y1, y2];
                                    }
                                    if (y1 &lt; y2) {
                                        liste.append({
                                            "x1": x1-d, "y1": y1+d,
                                            "x2": x1+d, "y2": y1-d,
                                            "x3": x2+d, "y3": y2-d,
                                            "x4": x2-d, "y4": y2+d,
                                            "f1": f1, "f2": f2
                                        });
                                    } else {
                                        liste.append({
                                            "x1": x1-d, "y1": y1-d,
                                            "x2": x1+d, "y2": y1+d,
                                            "x3": x2+d, "y3": y2+d,
                                            "x4": x2-d, "y4": y2-d,
                                            "f1": f1, "f2": f2
                                        });
                                    }
                                }
                            }

                            Repeater { // CHAQUE LIGNE DE CONTOUR
                                model: ListModel {id: cliste}
                                Shape {
                                    containsMode: Shape.FillContains
                                    HoverHandler {
                                        id: mouseCont
                                        cursorShape: Qt.CrossCursor
                                    }
                                    property int f1: model.f1
                                    property int f2: model.f2
                                    property var c: mouseCont.hovered ? "yellow" : "black"
                                    ShapePath {
                                        strokeWidth: 0.25
                                        strokeColor: c
                                        fillColor: c
                                        startX: model.x1
                                        startY: model.y1
                                        PathPolyline {
                                            path: [
                                                Qt.point(model.x2, model.y2),
                                                Qt.point(model.x3, model.y3),
                                                Qt.point(model.x4, model.y4),
                                                Qt.point(model.x1, model.y1),
                                            ]
                                        }
                                        pathHints: ShapePath.PathSolid || ShapePath.PathLinear || ShapePath.PathConvex;
                                    }
                                    TapHandler {
                                        onTapped: {
                                            faces.attache(num, f1, f2);
                                        }
                                    }
                                }
                                Component.onCompleted: creeLignes(lcont, cliste)
                            }

                            Repeater { // CHAQUE LIGNE DE PLI
                                model: ListModel {id: pliste}
                                Shape {
                                    containsMode: Shape.FillContains
                                    HoverHandler {
                                        id: mousePlis
                                        cursorShape: Qt.CrossCursor
                                    }
                                    property int f1: model.f1
                                    property int f2: model.f2
                                    property var c: mousePlis.hovered ? "red" : "white"
                                    ShapePath {
                                        strokeWidth: 0.25
                                        strokeColor: c
                                        fillColor: c
                                        startX: model.x1
                                        startY: model.y1
                                        PathPolyline {
                                            path: [
                                                Qt.point(model.x2, model.y2),
                                                Qt.point(model.x3, model.y3),
                                                Qt.point(model.x4, model.y4),
                                                Qt.point(model.x1, model.y1),
                                            ]
                                        }
                                        pathHints: ShapePath.PathSolid || ShapePath.PathLinear || ShapePath.PathConvex;
                                    }
                                    TapHandler {
                                        onTapped: {
                                            faces.detache(num, f1, f2);
                                        }
                                    }
                                }
                                Component.onCompleted: creeLignes(plis, pliste)
                            }

                            WheelHandler { // ALT + roulette pour tourner la pièce
                                acceptedModifiers: Qt.AltModifier
                                property: "rotation"
                                //targetTransformAroundCursor: false
                                rotationScale: 0.5
                            }
                        }
                    }
                    WheelHandler { // roulette pour zoomer la vue
                        //acceptedModifiers: Qt.ControlModifier
                        property: "scale"
                    }
                }

</code></pre>
]]></description><link>https://forum.qt.io/topic/165256/is-there-a-way-to-make-qml-use-2d-data-model</link><generator>RSS for Node</generator><lastBuildDate>Sat, 14 Nov 2026 00:01:59 GMT</lastBuildDate><atom:link href="https://forum.qt.io/topic/165256.rss" rel="self" type="application/rss+xml"/><pubDate>Tue, 10 Nov 2026 10:37:07 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Is there a way to make QML use 2D data model ? on Fri, 13 Nov 2026 20:07:10 GMT]]></title><description><![CDATA[<p dir="auto">the data class</p>
<pre><code>#ifndef PIECE_H
#define PIECE_H


#include &lt;QtCore/qobjectdefs.h&gt;
#include &lt;QtCore/qtmetamacros.h&gt;
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 &amp;) = default;
    piece(piece &amp;&amp;) = default;
    piece &amp;operator=(const piece &amp;) = default;
    piece &amp;operator=(piece &amp;&amp;) = default;
    explicit piece(const float &amp;x, const float &amp;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_H
</code></pre>
<p dir="auto">main.cpp</p>
<pre><code>#include "piece.h"
#include &lt;QRangeModel&gt;
#include &lt;QGuiApplication&gt;
#include &lt;QQmlApplicationEngine&gt;

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    QList&lt;piece&gt; mesPieces;
    mesPieces.append(piece(20.0f, 20.0f));
    mesPieces.append(piece(60.0f, 0.0f));
    mesPieces.append(piece(100.0f, 30.0f));
    QRangeModel modele(&amp;mesPieces);

    QQmlApplicationEngine engine;
    engine.setInitialProperties({{"monModele", QVariant::fromValue(&amp;modele) }});

    QObject::connect(
        &amp;engine,
        &amp;QQmlApplicationEngine::objectCreationFailed,
        &amp;app,
        []() { QCoreApplication::exit(-1); },
        Qt::QueuedConnection);
    engine.loadFromModule("testQRange1", "Main");

    return QGuiApplication::exec();
}
</code></pre>
<p dir="auto">main.qml</p>
<pre><code>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 }
            }
        }
    }
}
</code></pre>
<p dir="auto">It doesn't work if I try to replace mx and my properties by required property real x (and y)</p>
]]></description><link>https://forum.qt.io/post/840913</link><guid isPermaLink="true">https://forum.qt.io/post/840913</guid><dc:creator><![CDATA[Gilboonet]]></dc:creator><pubDate>Fri, 13 Nov 2026 20:07:10 GMT</pubDate></item><item><title><![CDATA[Reply to Is there a way to make QML use 2D data model ? on Fri, 13 Nov 2026 19:42:48 GMT]]></title><description><![CDATA[<p dir="auto">Can you share a minimal compilable application with your current code ?<br />
That would allow us to check what is going on.</p>
]]></description><link>https://forum.qt.io/post/840911</link><guid isPermaLink="true">https://forum.qt.io/post/840911</guid><dc:creator><![CDATA[SGaist]]></dc:creator><pubDate>Fri, 13 Nov 2026 19:42:48 GMT</pubDate></item><item><title><![CDATA[Reply to Is there a way to make QML use 2D data model ? on Fri, 13 Nov 2026 16:04:46 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/grecko">@<bdi>GrecKo</bdi></a> 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.</p>
<p dir="auto">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.</p>
]]></description><link>https://forum.qt.io/post/840910</link><guid isPermaLink="true">https://forum.qt.io/post/840910</guid><dc:creator><![CDATA[Gilboonet]]></dc:creator><pubDate>Fri, 13 Nov 2026 16:04:46 GMT</pubDate></item><item><title><![CDATA[Reply to Is there a way to make QML use 2D data model ? on Fri, 13 Nov 2026 13:01:12 GMT]]></title><description><![CDATA[<p dir="auto">You should follow the following section to expose your properties as roles:<br />
<a href="https://doc.qt.io/qt-6/qrangemodel.html#gadgets-and-objects-as-multi-role-items" target="_blank" rel="noopener noreferrer nofollow ugc">https://doc.qt.io/qt-6/qrangemodel.html#gadgets-and-objects-as-multi-role-items</a></p>
<p dir="auto">You should then be able to write <code>startY: model.y</code> (with a <code>required property QtObject model</code> in the delegate)</p>
]]></description><link>https://forum.qt.io/post/840907</link><guid isPermaLink="true">https://forum.qt.io/post/840907</guid><dc:creator><![CDATA[GrecKo]]></dc:creator><pubDate>Fri, 13 Nov 2026 13:01:12 GMT</pubDate></item><item><title><![CDATA[Reply to Is there a way to make QML use 2D data model ? on Fri, 13 Nov 2026 08:52:36 GMT]]></title><description><![CDATA[<p dir="auto">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.</p>
<pre><code>                startX: monModele.data(monModele.index(index,0), Qt.DisplayRole)
                startY: monModele.data(monModele.index(index,1), Qt.DisplayRole)
</code></pre>
<p dir="auto">Now I'm adding the 2d data part.</p>
]]></description><link>https://forum.qt.io/post/840906</link><guid isPermaLink="true">https://forum.qt.io/post/840906</guid><dc:creator><![CDATA[Gilboonet]]></dc:creator><pubDate>Fri, 13 Nov 2026 08:52:36 GMT</pubDate></item><item><title><![CDATA[Reply to Is there a way to make QML use 2D data model ? on Thu, 12 Nov 2026 21:18:15 GMT]]></title><description><![CDATA[<p dir="auto">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.</p>
]]></description><link>https://forum.qt.io/post/840902</link><guid isPermaLink="true">https://forum.qt.io/post/840902</guid><dc:creator><![CDATA[Gilboonet]]></dc:creator><pubDate>Thu, 12 Nov 2026 21:18:15 GMT</pubDate></item><item><title><![CDATA[Reply to Is there a way to make QML use 2D data model ? on Thu, 12 Nov 2026 19:53:38 GMT]]></title><description><![CDATA[<p dir="auto">I haven't used it in such a fashion yet but I think what you want is in the <a href="https://doc.qt.io/qt-6/qrangemodel.html#structs-and-gadgets-as-rows" target="_blank" rel="noopener noreferrer nofollow ugc">Structs and gadgets as rows chapter</a> In QRangeModel's documentation.</p>
]]></description><link>https://forum.qt.io/post/840901</link><guid isPermaLink="true">https://forum.qt.io/post/840901</guid><dc:creator><![CDATA[SGaist]]></dc:creator><pubDate>Thu, 12 Nov 2026 19:53:38 GMT</pubDate></item><item><title><![CDATA[Reply to Is there a way to make QML use 2D data model ? on Thu, 12 Nov 2026 15:53:14 GMT]]></title><description><![CDATA[<p dir="auto">I'm trying to use QRangeModel as it seems to be a very neat feature.</p>
<p dir="auto">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.</p>
<p dir="auto">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.</p>
<p dir="auto">Here's my code :<br />
main.cpp</p>
<pre><code>#include &lt;QGuiApplication&gt;
#include "piece.h"
#include &lt;QRangeModel&gt;
#include &lt;QQmlApplicationEngine&gt;
#include &lt;QVariant&gt;

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    QList&lt;Piece&gt; mesPieces;
    mesPieces.append(Piece(20, 20));
    mesPieces.append(Piece(60, 0));
    QRangeModel modele(&amp;mesPieces);

    QQmlApplicationEngine engine;
    engine.setInitialProperties({
        {"monModele", QVariant::fromValue(&amp;modele)}
    });

    QObject::connect(
        &amp;engine,
        &amp;QQmlApplicationEngine::objectCreationFailed,
        &amp;app,
        []() { QCoreApplication::exit(-1); },
        Qt::QueuedConnection);
    engine.loadFromModule("testDeleg2", "Main");

    return QGuiApplication::exec();
}
</code></pre>
<p dir="auto">piece.h (class header)</p>
<pre><code>#ifndef PIECE_H
#define PIECE_H

#include &lt;QtTypes&gt;

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_H
</code></pre>
<p dir="auto">QML</p>
<pre><code>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);
        }
    }
}
</code></pre>
<p dir="auto">The ListModels contains what the QRangeModel is supposed to have.<br />
Maybe do I need to add  getters ?</p>
]]></description><link>https://forum.qt.io/post/840898</link><guid isPermaLink="true">https://forum.qt.io/post/840898</guid><dc:creator><![CDATA[Gilboonet]]></dc:creator><pubDate>Thu, 12 Nov 2026 15:53:14 GMT</pubDate></item><item><title><![CDATA[Reply to Is there a way to make QML use 2D data model ? on Tue, 10 Nov 2026 20:08:54 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/sgaist">@<bdi>SGaist</bdi></a> Thank you, I'm going to try that as replacement of QAbstractListModel, I've found an example QML project using that class, apparently there's need to use role. I will post my progress.</p>
]]></description><link>https://forum.qt.io/post/840871</link><guid isPermaLink="true">https://forum.qt.io/post/840871</guid><dc:creator><![CDATA[Gilboonet]]></dc:creator><pubDate>Tue, 10 Nov 2026 20:08:54 GMT</pubDate></item><item><title><![CDATA[Reply to Is there a way to make QML use 2D data model ? on Tue, 10 Nov 2026 19:39:47 GMT]]></title><description><![CDATA[<p dir="auto">Hi,</p>
<p dir="auto">Are you looking for something like described in the <a href="https://doc.qt.io/qt-6/qtquick-modelviewsdata-cppmodels.html#qabstractitemmodel-subclass" target="_blank" rel="noopener noreferrer nofollow ugc">QAbstractItemModel Subclass</a> in the <code>Using C++ Models with Qt Quick Views</code> chapter of Qt's documentation ?</p>
]]></description><link>https://forum.qt.io/post/840869</link><guid isPermaLink="true">https://forum.qt.io/post/840869</guid><dc:creator><![CDATA[SGaist]]></dc:creator><pubDate>Tue, 10 Nov 2026 19:39:47 GMT</pubDate></item></channel></rss>