Search code examples
qtqmlqt-quickqabstractitemmodel

Using QAbstractItemModel to return QQuickPaintedItem for use in QML delegate


I implemented a subclass of QQuickPaintedItem to be used in QML which works on its own when registered through

qmlRegisterType<T>

Instances of this class are created at application startup and put into a QList that is stored inside a subclass of QAbstractItemModel. I thought I could easily return each of those objects in the model's data method and use them as the QML ListViews delegate. It now looks like this:

Model.cpp:

QVariant AbteilungsModel::data(const QModelIndex &index, int role) const
{
    if(index.isValid() && role == Qt::DisplayRole)
    {
        Abteilung* a = static_cast<Abteilung*>(index.internalPointer());
        return QVariant::fromValue(a);
    }
}

main.qml:

ListView {
    id: abteilungenListView
    anchors.fill: parent
    spacing: 5
    model: abteilungen
    delegate: modelData
}

I, of course, made the model available in QML via

void QQmlContext::setContextProperty(const QString & name, QObject * value)

but I don't know how to properly declare the ListViews delegate, since "modelData" doesn't work.

Does anyone have an idea if this is even possible or do you guys have a better solution? Any help is appreciated! :)


Solution

  • It might be possible, but it goes against the whole MVC idea. Your model shouldn't know about your delegates. As a simplified example:

    main.cpp

    #include <QGuiApplication>
    #include <QtQml>
    #include <QtQuick>
    
    class Abteilung : public QQuickPaintedItem
    {
        Q_OBJECT
    public:
        Abteilung() {
        }
    
        void paint(QPainter *painter) {
            painter->setPen(Qt::red);
            painter->drawRect(boundingRect().adjusted(0, 0, -painter->pen().width(), -painter->pen().width()));
        }
    };
    
    int main(int argc, char *argv[])
    {
        QGuiApplication app(argc, argv);
    
        qmlRegisterType<Abteilung>("Test", 1, 0, "Abteilung");
    
        QQmlApplicationEngine engine;
        engine.load(QUrl(QStringLiteral("qrc:///main.qml")));
    
        return app.exec();
    }
    
    #include "main.moc"
    

    main.qml

    import QtQuick 2.2
    import QtQuick.Controls 1.1
    import Test 1.0
    
    ApplicationWindow {
        visible: true
        width: 640
        height: 480
    
        ListView {
            id: abteilungenListView
            anchors.fill: parent
            spacing: 5
            model: ListModel {
                Component.onCompleted: {
                    for (var i = 0; i < 100; ++i) {
                        append({name: i});
                    }
                }
            }
    
            delegate: Abteilung {
                width: abteilungenListView.width
                height: 40
            }
        }
    }