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

2022-01-19 00:00:00 qt qml c++ qt5.7

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

I'm working on a simple project to try and learn QT 5.7, QML, and C++. I want to create a simple interface that has a list of items that I can add and remove items from using a couple of buttons. I've been reading a bunch of different guides online trying to piece together something but I keep getting stuck. I've tried using QQmlListProperty<T> and QAbstractListModel but I have questions about both approaches:

  1. 对于我的项目来说,QQmlListProperty<T> 是正确的,还是应该使用 QAbstractListModel?
  2. 对于这两种情况,如何通知我的 QML 视图列表已更改?
  3. 如果我使用QAbstractListModel",是否只需要创建 Q_INVOKABLE 方法来添加和删除列表中的项目?
  1. For my project is QQmlListProperty<T> the right thing to use or I should use QAbstractListModel?
  2. For either case how do I notify my QML view that the list has changed?
  3. If I use 'QAbstractListModel', do I just need to create Q_INVOKABLE methods for adding and removing items from my list?

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

Below is my code for both QQmlListProperty<T> and QAbstractListModel so far. I've left out most of the implementation of the classes to keep this post short but if the implementation is needed I'm happy to add it.

QQmlListProperty项目类

QQmlListProperty Item 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列表类

QQmlListProperty List 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 是大多数情况下的正确类,除非你确定你只会使用一个简单的列表.

I would generally suggest that QAbstractListModel is the right class to go with most of the time, unless you are sure you'll only be working with a simple list.

对于任何一种情况,我如何通知我的 QML 视图列表已更改?

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

QAbstractItemModel(QAbstractListModel 继承)有许多不同的方法,你应该从你的子类中调用这些方法来通知与其相连的视图发生了什么事.当您向其中插入项目时,您需要 QAbstractItemModel::beginInsertRows 和 QAbstractItemModel::endInsertRows.

QAbstractItemModel (which QAbstractListModel inherits) has a number of different methods that you should call from your subclass to inform the view(s) connected to it that something has happened. When you're inserting items to it, you want QAbstractItemModel::beginInsertRows and QAbstractItemModel::endInsertRows.

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

If your model is representing something simple, like a list of names for instance, your insertion might look something like this:

假设:

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 和 QAbstractItemModel::data 至少,但看起来你已经处理好了.如果要实现数据的编辑,还需要实现 QAbstractListModel::setData.

You then need to implement 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):

Once you've done that, register the type (using qmlRegisterType):

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

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

And then import & instantiate it from QML, and use it on your view:

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")
        }
    }
}

相关文章