I'm writing a proof of concept application, that is very simple. Basically it's composed of a UI where a list of "Note" type objects is displayed in a QML ListView.
I then have a few classes which is something along the lines:
#ifndef NOTE_H
#define NOTE_H
#include <string>
using namespace std;
class Note
{
public:
Note(QObject* parent = 0)
: QObject(parent)
{
}
Note(const int id, const string& text)
: _id(id), _text(text)
{
}
int id()
{
return _id;
}
const string text()
{
return _text;
}
void setText(string newText)
{
_text = newText;
}
private:
int _id;
string _text;
};
#endif // NOTE_H
Then a repository:
class NoteRepository : public Repository<Note>
{
public:
NoteRepository();
~NoteRepository();
virtual shared_ptr<Note> getOne(const int id);
virtual const unique_ptr<vector<Note>> getAll();
virtual void add(shared_ptr<Note> item);
private:
map<int, shared_ptr<Note>> _cachedObjects;
};
Finally a ViewModel that exposes Note to QML
class MainViewModel : public QObject
{
Q_OBJECT
Q_PROPERTY(QQmlListProperty<Note> notes READ notes NOTIFY notesChanged)
Q_PROPERTY(int count READ count() NOTIFY countChanged)
public:
MainViewModel(QObject *newParent = 0);
int count();
QQmlListProperty<Note> notes();
signals:
void notesChanged();
void countChanged();
public slots:
private:
std::shared_ptr<UnitOfWork> _unitOfWork;
static void appendNote(QQmlListProperty<Note> *list, Note *note);
QList<Note*> _notes;
};
PLEASE DON'T MIND ANY C++ MISTAKES HERE and mind they are incomplete, it's not the point at this moment as I'm constantly adapting this as I learn.
The point where I'm struggling is, how to expose a list-like object to QML? The requirement is this list must be dynamic, one should be able to add, delete and modify the text of a note. When the list is modified by C++, it should also notify the UI (signal).
I tried QQmlListProperty, but couldn't figure a way of exposing it to QML. Then I read on another SO post this type can't be modified by QML (??), and I stumbled upon QAbstractItemModel.
Anyhow, can anyone point me to the right direction?
I've posted a rather complete example in another answer.
The general procedure is:
Create a model that derives from
QAbstractItemModel
. You can reuse any of the models already provided by Qt, for exampleQStringListModel
.Expose it to QML. E.g. use
setContextProperty()
of QML Engine'srootContext()
.The model's roles are visible in the context of the delegate in QML. Qt provides default mapping between names and roles for the
DisplayRole
(display
) andEditRole
(edit
) in a default implementation ofroleNames()
.You can create intermediate viewmodels, if needed, by attaching proxy models between the views and the backend models. You can derive from
QAbstractProxyModel
or one of its subclasses.