A set of models extending the Qt model-view framework
- clone or download this repository
- add
include (<path/to/QModels>/QModels.pri)in your.pro import Eco.Tier1.Models 1.0to use this library in your QML files
QObjectListModel is a hard-fork of QOlm * Olivier LDff
QObjectListModel object based on QAbstractListModel that provide a list of QObject based class to qml and c++. The model dynamically update views by reacting to insert, remove, move operations.
QObjectListModel is based on QAbstractListModel, and behave as a list of custom QObject. QObjectModelBase is detail implementation to provide signals and slots that moc can handle. Since moc isn't working with template class.
Most of the time you want to store more than just QObject type, so create your custom type.
#include <QtCore/QObject>
class Foo : public QObject
{
Q_OBJECT
public:
Foo(QObject* parent = nullptr) : QObject(parent) {}
int foo = 0;
};Then use a QObjectListModel based object with class inheritance or as a typedef.
#include <Foo.h>
#include <QObjectListModel/QObjectListModel.h>
// Declare type
using FooList = QObjectListModel<Foo>;
// Or create custom class
class FooList : public QObjectListModel<Foo>
{
Q_OBJECT
public:
Foo(QObject* parent = nullptr,
const QList<QByteArray> & exposedRoles = {},
const QByteArray & displayRole = {}):
QObjectListModel<Foo>::(parent, exposedRoles, displayRole)
{
}
};Then simply use it as a regular list.
The object provide multiple way to insert an object in the list:
append: Add an object at the end of the list.prepend: Add an object at the beginning of the list.insert: Insert object at requested offset.
Those three functions can also take a QList<_Object*> as a parameter entry to insert multiple object at once.
FooList list;
Foo foo1;
Foo foo2;
Foo foo3;
Foo foo4;
// {foo1}
list.append(&foo1);
// {foo2, foo1}
list.prepend(&foo2);
// {foo2, foo1, foo3}
list.append(&foo3);
// {foo2, foo4, foo1, foo3}
list.insert(1, &foo4);To remove an item, simply call the remove function, either with a pointer to the _Object* , or with the index of the object at which you want to remove.
All elements can also be removed using clear function.
FooList list;
Foo foo1;
Foo foo2;
Foo foo3;
Foo foo4;
list.append({&foo1, &foo2, &foo3, &foo4});
// { &foo1, &foo2, &foo4 }
list.remove(&foo3);
// { &foo1, &foo2 }
list.remove(2);
// Remove all elements.
list.clear();Elements can be moved within the list, without changing the list size.
movefrom object at indexfromto indexto.moveUp: Move object at indexindextoindex-1. This function make sense when seeing the list in aListViewfor example. It move the item to previous index.moveDown: Move object fromindextoindex+1. This function make sense in aListViewin a column. It move the item to next index.moveNext: alias ofmoveDown.movePrevious: alias ofmoveUp.
FooList list;
Foo foo1;
Foo foo2;
Foo foo3;
Foo foo4;
list.append({&foo1, &foo2, &foo3, &foo4});
// { &foo1, &foo3, &foo4, &foo2 }
list.move(1, 3);
// { &foo2, &foo1, &foo3, &foo4 }
list.move(3, 0);
// { &foo2, &foo3, &foo1, &foo4 }
list.movePrevious(2);
// { &foo2, &foo3, &foo4, &foo1 }
list.moveNext(2);Multiple accessors can be used to get data.
get: Get pointer to the_Object*atindex.indexOf: Get theindexfrom a_Object*contains: Get if a_Object*is present.size: Give the number of objects in the modelempty: True if model is empty.
The library follow qt ownership rules. So when inserting an object without parent, the list take ownership of that object. When the same object is removed it will be deleteLater.
FooList list;
// list take ownership on new Foo
list.append(new Foo());
// Since FooList have ownership on the foo at index 0, it call deleteLater on it. No need to worry about memory management.
list.remove(0);The QObjectListModel derived object can be observe for insertion and deletion like any qt model.
But those signals are not very convenient to use as a end user. That's why QObjectListModel provide other way to observe the list.
QObjectListModel::QObjectModelBase provide basic signal to react to QObject insert/remove/move operation.
objectInserted(QObject* object, int index)objectRemoved(QObject* object, int index)objectMoved(QObject* object, int from, int to)
They are call when the model can safely be iterated. You can simply retrieve a correct pointer by using qobject_cast<_Object*>(object).
Sometime it can be useful to do some processing before the whole world gets notify about our object operation. This method is only available if you define a custom list type.
#include <Foo.h>
#include <QObjectListModel/QObjectListModel.h>
class FooList : public QObjectListModel<Foo>
{
Q_OBJECT
public:
FooList(QObject* parent = nullptr,
const QList<QByteArray> & exposedRoles = {},
const QByteArray & displayRole = {}):
QObjectListModel<Foo>(parent, exposedRoles, displayRole)
{
}
protected:
bool onObjectAboutToBeInserted(Foo* item, int row) override
{
// Item is not yet inserted, do some preinsert operation on it.
// if return false, item won't be inserted
}
void onObjectInserted(Foo* item, int row) override
{
// Item just got inserted, but no callback/signal have been called yet.
}
bool onObjectAboutToBeMoved(Foo* item, int src, int dest) override
{
// Item haven't move yet, and no callback/signal have been called yet
// if return false, item won't be moved
}
void onObjectMoved(Foo* item, int src, int dest) override
{
// Item have been moved. No Callback/Signal have been called yet.
}
bool onObjectAboutToBeRemoved(Foo* item, int row) override
{
// Item isn't removed yet, and no callback/signal have been called yet
// if return false, item won't be removed
}
void onObjectRemoved(Foo* item, int row) override
{
// Item have been removed. Callback/Signal have been called
}
};QObjectListModel provide lambda connection with already qobject_cast objects. This is the preferred and easier way to observe the list
FooList list;
// Preferred API, safer to use when giving a context
list.onInserted(&list, [](Foo* foo, int index){});
list.onInserted(&list, [](Foo* foo){});
list.onRemoved(&list, [](Foo* foo, int index){});
list.onRemoved(&list, [](Foo* foo){});
list.onMoved(&list, [](Foo* foo, int from, int to){});
// Should only be used when your callback doesn't require any context
list.onInserted([](Foo* foo, int index){});
list.onInserted([](Foo* foo){});
list.onRemoved([](Foo* foo, int index){});
list.onRemoved([](Foo* foo){});
list.onMoved([](Foo* foo, int from, int to){});When connecting without any
receiver, this list is used as the context.
QObjectListModel is compatible with modern iterator, you can simply do:
FooList list;
for(const auto* foo : list)
{
//foo->getFoo()
}
for(auto* foo : list)
{
//foo->setFoo(12)
}The same api as the c++ work in qml. Every Q_PROPERTY are exposed as role, and another role qtObject allow to access the QObject*.
For the following example to work Foo and FooList need to be registered to the qml system.
import QtQuick 2.0
import MyFoo 1.0
ListView {
width: 180; height: 200
FooList { id: _fooList }
model: _fooList
delegate: Text
{
// Access role qtObject and cast it to our type
property Foo fooObj : model.qtObject
text: index + ": " +
fooObj.foo + // Access via casted object
+ ", " +
foo // Access via role
}
Component.onCompleted:
{
_fooList.append(new Foo())
_fooList.insert(1, new Foo())
_fooList.prepend(new Foo())
}
}If you need to filter exposed roles, then use the constructor arguments. Same to set a display role.
//QObjectListModel(QObject* parent = nullptr,
// const QList<QByteArray> & exposedRoles = {},
// const QByteArray & displayRole = {})
// The following code expose foo as exposedRoles, and foo as Qt::DisplayRole
FooList list(nullptr, {"foo"}, "foo");It is recommended to only expose role that are required for QSortFilterProxyModel subclass. And use native signal to property for property that often change.
#include <QtCore/QObject>
class FooChild : public QObject
{
Q_OBJECT
public:
FooChild(QObject* parent = nullptr) : QObject(parent) {}
int fooChild = 0;
};
class Foo : public QObject
{
Q_OBJECT
Q_PROPERTY (QQmlListProperty<FooChild> childs READ getChilds CONSTANT)
public:
Foo(QObject* parent = nullptr) : QObject(parent) {}
const QObjectListProperty<FooChild> &getChilds() const
{
return m_childs;
}
QObjectListProperty<FooChild> m_childs;
};QModelHelper is a hard-fork of QmlModelHelper * oKcerG
Access your models from QML or C++ without views or delegates
To use the QModelHelper, use it as an attached object of a model (it must be a subclass of QAbstractItemModel, meaning it can originate from c++ or be a ListModel from QML). Or as a wrapper in C++.
These properties holds the number of rows in the model.
This property holds a boolean refering if the model is empty or not (emptyChanged is only emitted when count goes from 0 to x or x to 0.
Returns a live object mapping an index's data of the model. This is an object with read-write properties named as the model's roles.
If the index doesn't exist in the model, the properties will be undefined.
ComboBox {
id: control
model: vehiclesModel
readonly property QtObject currentData: vehiclesModel.ModelHelper.map(control.currentIndex)
contentItem: RowLayout {
id: contentItem
Image { source: control.currentData.imagePath }
Label { text: control.currentData.name }
}
delegate: ItemDelegate {
contentItem: RowLayout {
Image { source: model.imagePath }
Label { text: model.name }
}
highlighted: control.highlightedIndex == index
}
}
Returns the role number for the given roleName. If no role is found for this name, -1 is returned.
Returns the role name for the given role. If no role name is found for this role, an empty string is returned.
Return the item at row in the model as a map of all its roles.
This can be used in imperative code when you don't need the live updating provided by the map function. Only reading is supported.
Return the data for the given roleName of the item at row in the model.
Similar to get(int row) except that it queries only one role. Prefer this one if you don't need multiple roles for a row.
Changes the values at row in the list model with the values in values. Properties not appearing in newValues are left unchanged.
Changes the property at row in the list model to value.
Returns the first row index where value at columnName equals value.
Returns true if a row with the value at columnName equals value. Similar to int indexOf()
A dead-simple way to create a dynamic C++ list of any type and expose it to QML with the strong API of QAbstractListModel, way better than using a QVariantList property.
The type object is accessed with the modelData roleName.
Work in progress
Concatenates rows from multiple source models
TODO Adds columns after existing columns
TODO
A simplified QExtraColumnsProxyModel to add just a selected role column to a source model