After more experience with QML I've found the best way to have lists of things is with a QAbstractListModel
.
You make your Thing
derive from QObject
so it can be stored in a QVariant
(after registering it). Then you can return the actual Thing
as the model item. You can access it in a Repeater
as model.display.a_property_of_thing
. The list length is available as model.count
.
This has the following pros and cons:
- Fast - it doesn't copy the entire list to access one element.
- You can easily get animations for changes to the list (addition, rearrangement and removal of items).
- It's easy to use from QML.
- To enable the animations to work, whenever you change the list you have to do some slightly faffy bookkeeping (
beginInsertRows()
etc.)
...
class Things : public QObject
{
...
};
Q_DECLARE_METATYPE(Thing*)
class ThingList : public QAbstractListModel
{
Q_OBJECT
public:
explicit ThingList(QObject *parent = 0);
~ThingList();
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
public slots:
// Extra function to get the thing easily from outside Repeaters.
Thing* thing(int idx);
private:
QList<Thing*> mThings;
};
int ThingList::rowCount(const QModelIndex& parent) const
{
return mThings.size();
}
QVariant ThingList::data(const QModelIndex& index, int role) const
{
int i = index.row();
if (i < 0 || i >= mThings.size())
return QVariant(QVariant::Invalid);
return QVariant::fromValue(mThings[i]);
}
Thing* ThingList::thing(int idx)
{
if (idx < 0 || idx >= mThings.size())
return nullptr;
return mThings[idx];
}