Using TableView as ListView-delegate

2019-07-15 06:43发布

问题:

I have a model that contains several QStandardItemModels. Now I want to create a view that displays a TableView for each QStandardItemModel. I had the idea to have a ListView that has a TableView as delegate, something like this:

ListView {
    id: myListView

    anchors {
        fill: parent
        margins: 5
    }

    model: testModel
    delegate: CompareDelegate { }
}

And in CompareDelegate.qml:

Item {
    id: base

    width: 500
    height: 300

    TableView {
        anchors.fill: parent
    }
}

How do I get the TableView inside the delegate to use the appropriate QStandardItemModel within the model of the ListView? I hope the question is somewhat clear.

Thanks in advance.

回答1:

Interesting use case... I am still not sure if it's a good idea and am wondering if there's a better way to do it, but I couldn't think of reasons why it's bad, so I tried it out of curiosity:

main.cpp

#include <QApplication>
#include <QtQml>
#include <QtWidgets>

class IndividualModel : public QStandardItemModel
{
public:
    IndividualModel(QObject* parent = 0) :
        QStandardItemModel(4, 2, parent)
    {
        for (int row = 0; row < 4; ++row) {
            QStandardItem *item0 = new QStandardItem;
            item0->setData(QString("row %1, column 0").arg(row), TitleRole);
            setItem(row, 0, item0);

            QStandardItem *item1 = new QStandardItem;
            item1->setData(QString("row %1, column 1").arg(row), AuthorRole);
            setItem(row, 1, item1);
        }
    }

    enum {
        TitleRole = Qt::UserRole,
        AuthorRole
    };

    QHash<int, QByteArray> roleNames() const Q_DECL_OVERRIDE
    {
        QHash<int, QByteArray> names;
        names[TitleRole] = "title";
        names[AuthorRole] = "author";
        return names;
    }
};

class CompositeModel : public QAbstractItemModel
{
public:
    CompositeModel()
    {
        for (int i = 0; i < 3; ++i) {
            QStandardItemModel *model = new IndividualModel(this);
            mModels.append(model);
        }
    }

    enum {
        ModelRole = Qt::UserRole
    };

    QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE
    {
        if (!index.isValid())
            return QVariant();

        if (role != ModelRole)
            return QVariant();

        return QVariant::fromValue(mModels.at(index.row()));
    }

    QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE
    {
        if (!hasIndex(row, column, parent))
            return QModelIndex();

        return createIndex(row, column);
    }

    QModelIndex parent(const QModelIndex &) const Q_DECL_OVERRIDE
    {
        return QModelIndex();
    }

    int rowCount(const QModelIndex & = QModelIndex()) const Q_DECL_OVERRIDE
    {
        return mModels.size();
    }

    int columnCount(const QModelIndex & = QModelIndex()) const Q_DECL_OVERRIDE
    {
        return 1;
    }

    QHash<int, QByteArray> roleNames() const Q_DECL_OVERRIDE
    {
        QHash<int, QByteArray> names;
        names[ModelRole] = "individualModel";
        return names;
    }

private:
    Q_DISABLE_COPY(CompositeModel)

    QVector<QStandardItemModel*> mModels;
};

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

    QQmlApplicationEngine engine;

    CompositeModel compositeModel;
    engine.rootContext()->setContextProperty("compositeModel", QVariant::fromValue(&compositeModel));

    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    return app.exec();
}

main.qml

import QtQuick 2.0
import QtQuick.Window 2.0
import QtQuick.Controls 1.0

Window {
    visible: true
    width: 300
    height: 600

    ListView {
        anchors.fill: parent
        model: compositeModel
        delegate: TableView {
            model: individualModel

            TableViewColumn {
                role: "title"
                title: "Title"
                width: 100
            }
            TableViewColumn {
                role: "author"
                title: "Author"
                width: 200
            }
        }
    }
}

This works, but... it crashes on exit. :)

I've been unable to reproduce it while debugging with Creator, so I've only been able to get a stack trace manually on the command line with gdb, which I'm not too familiar with (have always used debuggers in IDEs :)). The crash is in QML's guts somewhere, while accessing some property. However, I've spent too much time on this to not post the answer, and I think it is still useful. Maybe some kind soul will find the problem and edit my post. :)