//Is this possible in any way? //Q_PROPERTY(AnimalModel modelAnimals READ modelAnimals NOTIFY modelAnimalsChanged)
Yes, right? Of course, this will not be AnimalModel , but a AnimalModel * , but as long as the model inherits QAbstractListModel , that’s all you need. You don’t even need the NOTIFY part, as changes internal to the model will be automatically reflected. modelAnimalsChanged only makes sense when replacing the entire model with another model and, naturally, by including QML warnings about using the property without notification. A cleaner way to do the latter when the model object does not change is to simply return AnimalModel * from the slot or Q_INVOKABLE .
If you want a truly flexible model, you can create one that stores QObject * , and then from QML you can create arbitrary objects with arbitrary properties and add to the model. Then from the model, you have one object role that returns an object, and you can query and use the object to get the properties that it has. While the implementation of the “classical” list model will define a model with a static fixed scheme, using this approach allows you to have “amorphous” objects in a model with different properties.
Naturally, this requires a certain type safety, for example, for each object in such a model there is a property int type , and based on this you can determine the available properties for the object. My usual approach is to have a Loader for the delegate and pass the object as a data source for various implementations of the QML interface, visualizing this type of object that it creates. Thus, you have both different objects in the model, and different QML elements as view delegates.
The last step to create the final object is “a piece of all deals” is the QQmlListProperty object and Q_CLASSINFO("DefaultProperty", "container") for it, which allows you to dynamically create a list / model or use the declarative QML syntax. Also note that with this solution you can add or remove from such a model, even delete declaratively created objects.
Also, depending on your usage scenario, you may need either qmlRegisterType() or qmlRegisterUncreatableType() for the model.
OK, at first glance, it seems that the "model of any data" you did not mean models without a scheme, but simply different schemes. In this case, instead of returning AnimalModel * you can use QAbstractListModel * or even QObject * - it will still work in QML, since it uses dynamism through the metasystem. But, in any case, models that do not have a scheme are much more powerful and flexible, and they do not need C ++ code that can be defined, it can only work with QML.
class List : public QAbstractListModel { Q_OBJECT QList<QObject *> _data; Q_PROPERTY(int size READ size NOTIFY sizeChanged) Q_PROPERTY(QQmlListProperty<QObject> content READ content) Q_PROPERTY(QObject * parent READ parent WRITE setParent) Q_CLASSINFO("DefaultProperty", "content") public: List(QObject *parent = 0) : QAbstractListModel(parent) { } int rowCount(const QModelIndex &p) const { Q_UNUSED(p) return _data.size(); } QVariant data(const QModelIndex &index, int role) const { Q_UNUSED(role) return QVariant::fromValue(_data[index.row()]); } QHash<int, QByteArray> roleNames() const { static QHash<int, QByteArray> * pHash; if (!pHash) { pHash = new QHash<int, QByteArray>; (*pHash)[Qt::UserRole + 1] = "object"; } return *pHash; } int size() const { return _data.size(); } QQmlListProperty<QObject> content() { return QQmlListProperty<QObject>(this, _data); } public slots: void add(QObject * o) { int i = _data.size(); beginInsertRows(QModelIndex(), i, i); _data.append(o); o->setParent(this); sizeChanged(); endInsertRows(); } void insert(QObject * o, int i) { beginInsertRows(QModelIndex(), i, i); _data.insert(i, o); o->setParent(this); sizeChanged(); endInsertRows(); } QObject * take(int i) { if ((i > -1) && (i < _data.size())) { beginRemoveRows(QModelIndex(), i, i); QObject * o = _data.takeAt(i); o->setParent(0); sizeChanged(); endRemoveRows(); return o; } else qDebug() << "ERROR: take() failed - object out of bounds!"; return 0; } QObject * get(int i) { if ((i > -1) && (i < _data.size())) return _data[i]; else qDebug() << "ERROR: get() failed - object out of bounds!"; return 0; } signals: void sizeChanged(); };
Then, after you qmlRegisterType<List>("Core", 1, 0, "List"); you can use it almost the way you want, it will contain any QObject or derivative, including QMLs QtObject It can be directly used as a model for the ListView drive. You can fill it dynamically using slots or declarative, for example:
List { QtObject { ... } QtObject { ... } List { QtObject { ... } QtObject { ... } } }
It will also handle ownership of objects, and you can easily nest it, creating essentially a separate tree model - note that you cannot declaratively do this with the QML ListModel . You can add a parentChanged signal and implement a setter that emits it if you want to associate it with a changing parent, in my case it was not necessary.
How to use it with a view, you can use the objectName property or int type property and use Loader for the delegate:
Loader { width: childrenRect.width height: childrenRect.height }
If you use the name of the object, you force the loader to create the name.qml file; if you use int, you can create an array of Component and use the corresponding index as the source component. You can either show object as a Loader property and specify the actual object of the UI link to it parent.object.prop , or you can use setSource(name + ".qml", {"object": object}) and have the object property directly in this element, however, setSource will only work with external sources, not with the built-in Component s. Please note that in the case of an external source, the object will be accessible even without any action for sending it, however for some reason it does not work with built-in components, and with such components the only possible way is to show it as a property of the loader.