1

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

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

以下是我迄今为止QQmlListProperty<T>的代码。QAbstractListModel我省略了大部分类的实现以保持这篇文章的简短,但如果需要实现,我很乐意添加它。

QQmlListProperty物品等级

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 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;
};
4

1 回答 1

4

我通常会建议 QAbstractListModel 是大多数时候使用的正确类,除非你确定你只会使用一个简单的列表。

无论哪种情况,我如何通知我的 QML 视图列表已更改?

QAbstractItemModel(QAbstractListModel 继承)有许多不同的方法,你应该从你的子类中调用这些方法来通知连接到它的视图发生了某些事情。当您向其中插入项目时,您需要QAbstractItemModel::beginInsertRowsQAbstractItemModel::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::rowCountQAbstractItemModel::roleNamesQAbstractItemModel::data,但看起来您已经处理好了。如果要实现数据编辑,还需要实现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")
        }
    }
}
于 2017-01-12T17:01:40.383 回答