Remove rows from QAbstractListModel

前端 未结 1 775
梦毁少年i
梦毁少年i 2020-12-18 04:55

I have a custom model which derives from QAbstractListModel which is exposed to QML. I need to support operations to add new items and remove existing items. While insertion

相关标签:
1条回答
  • 2020-12-18 05:27

    The code below works fine for me. Your problem is probably elsewhere. This is for Qt 5 due to use of Qt Quick Controls.

    There are two views accessing the same model, this visually confirms that the model emits proper signals to inform the views of the changes. The page additions and removals are done via the standard insertRows and removeRows methods, exported through Q_INVOKABLE. There's no need for any custom methods on this model, so far. The Q_INVOKABLE is a workaround for some missing functionality for the interface between QML and QAbstractItemModel.

    screenshot

    main.cpp

    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include <QQuickWindow>
    #include <QAbstractListModel>
    #include <QQmlContext>
    #include <QtQml>
    
    class GPage : public QObject {
        Q_OBJECT
        Q_PROPERTY(QString name NOTIFY nameChanged MEMBER m_name)
        Q_PROPERTY(int number NOTIFY numberChanged MEMBER m_number)
        QString m_name;
        int m_number;
    public:
        GPage(QObject * parent = 0) : QObject(parent), m_number(0) {}
        GPage(QString name, int number, QObject * parent = 0) :
            QObject(parent), m_name(name), m_number(number) {}
        Q_SIGNAL void nameChanged(const QString &);
        Q_SIGNAL void numberChanged(int);
    };
    
    class PageModel : public QAbstractListModel {
        Q_OBJECT
        QList<GPage*> m_pageList;
    public:
        PageModel(QObject * parent = 0) : QAbstractListModel(parent) {}
        ~PageModel() { qDeleteAll(m_pageList); }
        int rowCount(const QModelIndex &) const Q_DECL_OVERRIDE {
            return m_pageList.count();
        }
        QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE {
            if (role == Qt::DisplayRole || role == Qt::EditRole) {
                return QVariant::fromValue<QObject*>(m_pageList.at(index.row()));
            }
            return QVariant();
        }
        bool setData(const QModelIndex &index, const QVariant &value, int role) Q_DECL_OVERRIDE {
            Q_UNUSED(role);
            GPage* page = value.value<GPage*>();
            if (!page) return false;
            if (page == m_pageList.at(index.row())) return true;
            delete m_pageList.at(index.row());
            m_pageList[index.row()] = page;
            QVector<int> roles;
            roles << role;
            emit dataChanged(index, index, roles);
            return true;
        }
        Q_INVOKABLE bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()) Q_DECL_OVERRIDE {
            Q_UNUSED(parent);
            beginInsertRows(QModelIndex(), row, row + count - 1);
            for (int i = row; i < row + count; ++ i) {
                QString const name = QString("Page %1").arg(i + 1);
                GPage * page = new GPage(name, i + 1, this);
                m_pageList.insert(i, page);
                QQmlEngine::setObjectOwnership(page, QQmlEngine::CppOwnership);
            }
            endInsertRows();
            return true;
        }
        Q_INVOKABLE bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) Q_DECL_OVERRIDE {
            Q_UNUSED(parent);
            beginRemoveRows(QModelIndex(), row, row + count - 1);
            while (count--) delete m_pageList.takeAt(row);
            endRemoveRows();
            return true;
        }
    };
    
    int main(int argc, char *argv[])
    {
        PageModel model1;
        QGuiApplication app(argc, argv);
        QQmlApplicationEngine engine;
        model1.insertRows(0, 1);
        engine.rootContext()->setContextProperty("model1", &model1);
        qmlRegisterType<GPage>();
        engine.load(QUrl("qrc:/main.qml"));
        QObject *topLevel = engine.rootObjects().value(0);
        QQuickWindow *window = qobject_cast<QQuickWindow *>(topLevel);
        window->show();
        return app.exec();
    }
    
    #include "main.moc"
    

    main.qml

    import QtQuick 2.0
    import QtQml.Models 2.1
    import QtQuick.Controls 1.0
    
    ApplicationWindow {
        width: 300; height: 300
        Row {
            width: parent.width
            anchors.top: parent.top
            anchors.bottom: column.top
            Component {
                id: commonDelegate
                Rectangle {
                    width: view.width
                    implicitHeight: editor.implicitHeight + 10
                    color: "transparent"
                    border.color: "red"
                    border.width: 2
                    radius: 5
                    TextInput {
                        id: editor
                        anchors.margins: 1.5 * parent.border.width
                        anchors.fill: parent
                        text: edit.name // "edit" role of the model, to break the binding loop
                        onTextChanged: {
                            display.name = text;
                            model.display = display
                        }
                    }
                }
            }
            ListView {
                id: view
                width: parent.width / 2
                height: parent.height
                model: DelegateModel {
                    id: delegateModel1
                    model: model1
                    delegate: commonDelegate
                }
                spacing: 2
            }
            ListView {
                width: parent.width / 2
                height: parent.height
                model: DelegateModel {
                    model: model1
                    delegate: commonDelegate
                }
                spacing: 2
            }
        }
        Column {
            id: column;
            anchors.bottom: parent.bottom
            Row {
                Button {
                    text: "Add Page";
                    onClicked: model1.insertRows(delegateModel1.count, 1)
                }
                Button {
                    text: "Remove Page";
                    onClicked: model1.removeRows(pageNo.value - 1, 1)
                }
                SpinBox {
                    id: pageNo
                    minimumValue: 1
                    maximumValue: delegateModel1.count;
                }
            }
        }
    }
    

    main.qrc

    <RCC>
        <qresource prefix="/">
            <file>main.qml</file>
        </qresource>
    </RCC>
    
    0 讨论(0)
提交回复
热议问题