Generally, there are two distinctive ways how to define, create and attach the data model in the C++/Qt/QML model/delegate/view architecture. Let's illustrate them on a table view example:
#1. Inherite own C++/Qt class from QAbstractItemModel (or from its specialized children QAbstractTableModel for our example), define own C++/Qt/SQL/XML/JSON/etc data source/storage and re/write the necessary Qt model virtual methods to secure the upward/downward data flow. Then just initialize the model property of QML TableView when QML engine starts.
or
#2. Define own QML model using QML TableModel/TableModelColumn, fill the QML TableModel rows property with some static data or append/insert/remove some dynamic data using the QML TableModel's data manipulation methods. Then just refer such a QML TableModel from QML TableView.
And my questions are as follows:
Q1: Can I call the Qt QAbstractTableModel's data(index, role) and setData(index, value, role) methods and QML TableModel's data(index, role) and setData(index, value, role) methods from my QML JavaScript code the same way for both model definition options as described above? Hint: my impressions after extensive tests are that data()/setData() in QML JavaScript works just with QML TableModel, not for Qt QAbstractTableModel ...
Q2: If the answer for Q1 was YES (I pray-), how the C++/Qt QVariant is to be cast/converted/treated on the QML JavaScript side? The Qt QAbstractItemModel data()/setData() interchange all data as QVariants ...
Thank you for your expertize, this is described very confusing way in the Qt/QML documentation or, better said, not described at all ...
Yes, QML's TableModel
methods work similar to a custom QAbstractTableModel
. This is because the former inherits the latter. You can find the sources of QML's TableModel
in Qt sources. (For Qt 6 it's in qtdeclarative/src/labs/models
, files qqmltablemodel_p.h
and qqmltablemodel.cpp
. The corresponding class is called QQmlTableModel
in C++.)
Implementing a custom QAbstractTableModel
is not necessarily an easy thing to do, especially if the table is editable, cell-wise or structurally. However, in practice, it's practical to go this route since it also bridges QML GUI and underlying C++ business logic.
I must mention that you aren't supposed to call data
and setData
directly. Qt model system has the concept of "roles" which are exposed in QML code as properties of view delegates. The assortment of necessary roles as well as various features of a particular model (including cell editability) is configured when implementing QAbstractTableModel
. Ordinarily, the predefined roles like display
or edit
are enough. So, a read-only model which uses the predefined display
role (Qt::DisplayRole
in C++) can be used like this in QML:
TableView {
// ...
delegate: Label {
text: display
}
}
In this setup, QML will call data
with Qt::DisplayRole
argument for you.
setData
will be called when assigning the display
property. When referring to the role in a more deeply nested QML element, you might need to qualify the property:
TableView {
// ...
delegate: Label {
id: delegateRoot
required property var model
text: delegateRoot.model.display
}
}
Qt has an official guide to model writing and unfortunately you'll have to read a lot of it to make a functional custom model. Qt tutorials and examples available in Qt Creator's Welcome page are helpful too.
QVariant
conversion is transparent in QML. It does support JavaScript arrays and objects, but I'd recommend to limit yourself to primitive types since it's a UI model in the end, not business logic model.