0

trying to nest models to make one list and the other model to act as rows within the outer list. it works a bit, but i get corrupt data when i reset the outer model.

both models are C++. There is one outer model, but for each list item, another model is created. the second is dynamic.

main.qml:

import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtQuick.Layouts 1.2

ApplicationWindow
{
    visible: true
    width: 640
    height: 480

    property int lastW: 0
    property int lastH: 0

    function doLayout()
    {
        if (width != lastW || height != lastH)
        {
            lastH = height;
            lastW = width;

            // if this is omitted, everything works
            myModel.changed();
        }
    }

    onHeightChanged: doLayout();
    onWidthChanged: doLayout();

    // the outer list
    ListView
    {
        anchors.fill: parent
        model: myModel
        delegate: Thing1 { me: index; name: model.name }
    }
}

Thing1.qml

import QtQuick 2.5
import QtQuick.Controls 1.4
import com.example.qml 1.0

Item
{
    id: thing1
    width: parent.width
    height: 150

    property int me
    property string name

    Column
    {
        width: parent.width;

        Label
        {
            width: parent.width
            height: 50
            text: name
        }

        Item
        {
            width: parent.width;
            height: 100

            // use the row model to space boxes on the row
            Repeater
            {
                model: myModel.getRowModel()
                delegate: Thing2 { x: model.position }
            }
        }
    }        
}

Thing2.qml

import QtQuick 2.5
import QtQuick.Controls 1.4

Item
{
    id: thing2
    width: 100
    height: 100

    Rectangle
    {
        anchors.fill: parent
        color: "blue"
    }
}

the C++ models, mymodel.h

#include <QAbstractListModel>
#include <QQmlApplicationEngine>
#include <QObject>
#include <QString>
#include <QDebug>

class RowModel : public QAbstractListModel
{
    Q_OBJECT

public:

    int rowCount(const QModelIndex& parent = QModelIndex()) const override
    {
        return 3;
    }  

    QVariant data(const QModelIndex &index, int role) const override
    {
        // space out on the row
        int ix = index.row();
        return ix*110;
    }

    QHash<int, QByteArray> roleNames() const override
    {
        QHash<int, QByteArray> roles;
        roles[Qt::UserRole+1] = "position";
        return roles;
    }
};


class MyModel : public QAbstractListModel
{
    Q_OBJECT

public:

    int rowCount(const QModelIndex& parent = QModelIndex()) const override
    {
        return 3;
    }  

    QVariant data(const QModelIndex &index, int role) const override
    {
        int ix = index.row();
        if (ix < 1) return "Larry";
        if (ix < 2) return "Barry";
        return "Gary";
    }

    QHash<int, QByteArray> roleNames() const override
    {
        QHash<int, QByteArray> roles;
        roles[Qt::UserRole+1] = "name";
        return roles;
    }

    Q_INVOKABLE void changed()
    {
        beginResetModel();
        endResetModel();
    }

    Q_INVOKABLE RowModel* getRowModel()
    {
        // make a model for the row
        return new RowModel();
    }
};

and finally, main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <qqmlcontext.h>
#include <qqmlengine.h>
#include <qqmlcontext.h>
#include <qqml.h>
#include <QtQuick/qquickitem.h>
#include <QtQuick/qquickview.h>
#include "mymodel.h"

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

        MyModel model;

        qmlRegisterType<RowModel>("com.example.qml", 1, 0, "RowModel");

        QQmlContext* ctxt = engine.rootContext();
        ctxt->setContextProperty("myModel",  &model);
        engine.addImportPath(":/.");
        engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
        return app.exec();
    }

this is what i see:

running image

Then resize the window a bit and you will get the following:

qrc:/Thing1.qml:8: TypeError: Cannot read property of null
qrc:/main.qml:35:45: Unable to assign [undefined] to QString
qrc:/Thing1.qml:8: TypeError: Cannot read property of null
qrc:/main.qml:35:45: Unable to assign [undefined] to QString
qrc:/Thing1.qml:8: TypeError: Cannot read property of null
qrc:/main.qml:35:45: Unable to assign [undefined] to QString
qrc:/Thing1.qml:8: TypeError: Cannot read property of null
qrc:/main.qml:35:45: Unable to assign [undefined] to QString
qrc:/Thing1.qml:8: TypeError: Cannot read property of null
qrc:/main.qml:35:45: Unable to assign [undefined] to QString
qrc:/Thing1.qml:8: TypeError: Cannot read property of null
qrc:/main.qml:35:45: Unable to assign [undefined] to QString

What happens is that the model variable in main.qml somehow becomes lost and becomes null. not sure how this can happen.

here's a gist link with the actual files, https://gist.github.com/anonymous/a837957207f08f73c4bd29f1d00843df

thanks for any help.

jkj yuio
  • 2,543
  • 5
  • 32
  • 49
  • I built and ran your project and adjusted the window size but I couldn't see any error like above. My environment is Qt5.6 for OSX. – DenimPowell May 19 '16 at 09:40
  • I think it's to do with garbage collection, so it might be different on some systems. im running windows 8.1. can you try repeatedly resizing the window very small and back again a few tmes. thanks for looking at it. – jkj yuio May 19 '16 at 10:10
  • I tried as you said but It works without problem on my OSX. – DenimPowell May 20 '16 at 00:24

0 Answers0