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

会有一股神秘感。 提交于 2019-12-06 15:12:02

问题


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. 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?

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

Implementation of 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;
};

回答1:


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.

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

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:

Assuming:

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();
}

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.

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

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

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


来源:https://stackoverflow.com/questions/41617677/adding-and-removing-items-from-a-c-list-in-qml-qt-5-7

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!