在 QML/QT 5.7 中添加和删除 C++ 列表中的项目

Adding and removing items from a C++ list in QML/QT 5.7

我正在做一个简单的项目来尝试学习 QT 5.7、QML 和 C++。我想创建一个简单的界面,其中包含一个项目列表,我可以使用几个按钮添加和删除项目。我一直在网上阅读一堆不同的指南,试图拼凑一些东西,但我一直被卡住了。我试过使用 QQmlListProperty<T>QAbstractListModel 但我对这两种方法都有疑问:

  1. 对于我的项目来说 QQmlListProperty<T> 是正确的选择还是我应该使用 QAbstractListModel?
  2. 无论哪种情况,我如何通知我的 QML 视图列表已更改?
  3. 如果我使用 'QAbstractListModel',是否只需要创建 Q_INVOKABLE 方法来添加和删除列表中的项目?

下面是我目前针对 QQmlListProperty<T>QAbstractListModel 的代码。我省略了 类 的大部分实现以保持此 post 简短,但如果需要实现,我很乐意添加它。

QQmlListProperty 项目 Class

class PlaylistItemModel : public QObject
{
        Q_OBJECT
        Q_PROPERTY(QString name READ getName WRITE setName NOTIFY nameChanged)
    public:
        explicit PlaylistItemModel(QObject *parent = 0);
        QString getName();
        void setName(const QString &name);

    signals:
        void nameChanged();

    public slots:

    private:
        QString _name;
};

QQmlListProperty 列表 Class

class PlaylistModel : public QObject
{
        Q_OBJECT
        Q_PROPERTY(QQmlListProperty<PlaylistItemModel> items READ getItems NOTIFY itemsChanged)
    public:
        explicit PlaylistModel(QObject *parent = 0);
        QQmlListProperty<PlaylistItemModel> getItems() const;
        Q_INVOKABLE void addItem(PlaylistItemModel *item);
        Q_INVOKABLE void removeItem(PlaylistItemModel *item);
        Q_INVOKABLE void clearItems();

        static void append(QQmlListProperty<PlaylistItemModel> *list, PlaylistItemModel *item);
        static PlaylistItemModel* at(QQmlListProperty<PlaylistItemModel> *list, int index);
        static int count(QQmlListProperty<PlaylistItemModel> *list);
        static void clear(QQmlListProperty<PlaylistItemModel> *list);

    signals:
        void itemsChanged();

    public slots:

    private:
        QList<PlaylistItemModel*> _items;
};

实施getItms()

QQmlListProperty<PlaylistItemModel> PlaylistModel::getItems() const
{
    return QQmlListProperty<PlaylistItemModel>(this, _items, &append, &count, &at, &clear);
}

QAbstractListModel

class MyModel : public QAbstractListModel
{
    Q_OBJECT
    public:
        enum ModelRoles
        {
            ItemRole = Qt::UserRole + 1
        };

        MyModel(QObject *parent = 0);

        // QAbstractItemModel interface
        int rowCount(const QModelIndex &parent) const;
        QVariant data(const QModelIndex &index, int role) const;
        QHash<int, QByteArray> roleNames() const;

    private:
        QList<QString> _listData;
        QString itemAt(const QModelIndex &index) const;
};

我通常会建议 QAbstractListModel 在大多数情况下是正确的 class,除非您确定您只会使用一个简单的列表。

For either case how do I notify my QML view that the list has changed?

QAbstractItemModel(QAbstractListModel 继承)有许多不同的方法,您应该从您的 subclass 调用这些方法以通知与其连接的视图发生了某些事情。当您向其中插入项目时,您需要 QAbstractItemModel::beginInsertRows and QAbstractItemModel::endInsertRows.

如果您的模型代表的是一些简单的东西,例如姓名列表,您的插入可能看起来像这样:

假设:

class MyModel : public QAbstractListModel
{
public:
    Q_INVOKABLE void addPerson(const QString &name);
private:
    QVector<QString> m_names;
};

void MyModel::addPerson(const QString &name)
{
    beginInsertRows(QModelIndex(), m_names.count(), m_names.count());
    m_names.append(name);
    endInsertRows();
}

然后您需要实施 QAbstractItemModel::rowCount, QAbstractItemModel::roleNames, and QAbstractItemModel::data at a minimum, but it looks like you've already got that handled. If you want to implement editing of data, you also want to implement QAbstractListModel::setData

完成后,注册类型(使用 qmlRegisterType):

qmlRegisterType<MyModel>("MyModelImport", 1, 0, "MyModel");

然后从 QML 导入并实例化它,并在您的视图中使用它:

import MyModelImport 1.0
import QtQuick 2.6

ListView {
    id: listView
    anchors.fill: parent
    model: MyModel {
    }
    delegate: TextInput {
        text: model.text
        onEditingFinished: {
            // when the text is edited, save it back to the model (which will invoke the saveData we overloaded)
            model.text = text
        }
    }

    Rectangle {
        height: 100
        width: 400
        color: "red"
        Text {
            text: "Add item"
        }
        MouseArea {
            anchors.fill: parent
            onClicked: listView.model.addName("Some new name")
        }
    }
}