Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
cppmodels.qdoc
Go to the documentation of this file.
1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
3
4/*!
5\page qtquick-modelviewsdata-cppmodels.html
6\title Using C++ Models with Qt Quick Views
7\brief using Qt Quick views with models defined in C++
8
9
10\section1 Data Provided In A Custom C++ Model
11
12Models can be defined in C++ and then made available to QML. This is useful
13for exposing existing C++ data models or otherwise complex datasets to QML.
14
15A C++ model class can be defined as a \l QStringList, a \l {QVariant::}{QVariantList}, a
16QObjectList or a \l QAbstractItemModel. The first three are useful for exposing
17simpler datasets, while QAbstractItemModel provides a more flexible solution for
18more complex models.
19
20Here is a video tutorial that takes you through the whole process of exposing a C++
21model to QML:
22
23\youtube 9BcAYDlpuT8
24
25\section2 QStringList-based Model
26
27A model may be a simple \l QStringList, which provides the contents of the list
28via the \e modelData role.
29
30Here is a ListView with a delegate that references its model item's
31value using the \c modelData role:
32
33\snippet models/stringlistmodel/view.qml 0
34
35A Qt application can load this QML document and set the value of \c myModel
36to a QStringList:
37
38\snippet models/stringlistmodel/main.cpp 0
39
40The complete source code for this example is available in
41\l {models/stringlistmodel}{examples/quick/models/stringlistmodel}
42within the Qt install directory.
43
44\note There is no way for the view to know that the contents of a QStringList
45have changed. If the QStringList changes, it will be necessary to reset
46the model by setting the view's \c model property again.
47
48\section2 QVariantList-based Model
49
50A model may be a single \l {QVariant::}{QVariantList}, which provides the contents
51of the list via the \e modelData role.
52
53The API works just like with \l QStringList, as shown in the previous section.
54
55\note There is no way for the view to know that the contents of a QVariantList
56have changed. If the QVariantList changes, it will be necessary to reset
57the model.
58
59\section2 QObjectList-based Model
60
61A list of QObject* values can also be used as a model. A QList<QObject*> provides
62the properties of the objects in the list as roles.
63
64The following application creates a \c DataObject class with
65Q_PROPERTY values that will be accessible as named roles when a
66QList<DataObject*> is exposed to QML:
67
68\snippet models/objectlistmodel/dataobject.h 0
69\dots 4
70\snippet models/objectlistmodel/dataobject.h 1
71\codeline
72\snippet models/objectlistmodel/main.cpp 0
73\dots
74
75The QObject* is available as the \c modelData property. As a convenience,
76the properties of the object are also made available directly in the
77delegate's context. Here, \c view.qml references the \c DataModel properties in
78the ListView delegate:
79
80\snippet models/objectlistmodel/view.qml 0
81
82Note the use of the \c color property. You can require existing properties
83by declaring them as \c required in a derived type.
84
85The complete source code for this example is available in
86\l {models/objectlistmodel}{examples/quick/models/objectlistmodel}
87within the Qt install directory.
88
89Note: There is no way for the view to know that the contents of a QList
90has changed. If the QList changes, it is necessary to reset
91the model by setting the \c model property again.
92
93
94\section2 QAbstractItemModel Subclass
95
96A model can be defined by subclassing QAbstractItemModel. This is the
97best approach if you have a more complex model that cannot be supported
98by the other approaches. A QAbstractItemModel can also automatically
99notify a QML view when the model data changes.
100
101The roles of a QAbstractItemModel subclass can be exposed to QML by
102reimplementing QAbstractItemModel::roleNames().
103
104Here is an application with a QAbstractListModel subclass named \c AnimalModel,
105which exposes the \e type and \e sizes roles. It reimplements
106QAbstractItemModel::roleNames() to expose the role names, so that they can be
107accessed via QML:
108
109\snippet models/abstractitemmodel/model.h 0
110\dots
111\snippet models/abstractitemmodel/model.h 1
112\dots
113\snippet models/abstractitemmodel/model.h 2
114\codeline
115\snippet models/abstractitemmodel/model.cpp 0
116\codeline
117\snippet models/abstractitemmodel/main.cpp 0
118\dots
119
120This model is displayed by a ListView delegate that accesses the \e type and \e size
121roles:
122
123\snippet models/abstractitemmodel/view.qml 0
124
125QML views are automatically updated when the model changes. Remember the model
126must follow the standard rules for model changes and notify the view when
127the model has changed by using QAbstractItemModel::dataChanged(),
128QAbstractItemModel::beginInsertRows(), and so on. See the \l {Model subclassing reference} for
129more information.
130
131The complete source code for this example is available in
132\l {models/abstractitemmodel}{examples/quick/models/abstractitemmodel}
133within the Qt install directory.
134
135QAbstractItemModel presents a hierarchy of tables, but the views currently provided by QML
136can only display list data.
137In order to display the child lists of a hierarchical model,
138use the DelegateModel QML type, which provides the following properties and functions to be used
139with list models of QAbstractItemModel type:
140
141\list
142\li \e hasModelChildren role property to determine whether a node has child nodes.
143\li \l DelegateModel::rootIndex allows the root node to be specified
144\li \l DelegateModel::modelIndex() returns a QModelIndex which can be assigned to DelegateModel::rootIndex
145\li \l DelegateModel::parentModelIndex() returns a QModelIndex which can be assigned to DelegateModel::rootIndex
146\endlist
147
148\section2 SQL Models
149
150Qt provides C++ classes that support SQL data models. These classes work
151transparently on the underlying SQL data, reducing the need to run SQL
152queries for basic SQL operations such as create, insert, or update.
153For more details about these classes, see \l{Using the SQL Model Classes}.
154
155Although the C++ classes provide complete feature sets to operate on SQL
156data, they do not provide data access to QML. So you must implement a
157C++ custom data model as a subclass of one of these classes, and expose it
158to QML either as a type or context property.
159
160\section3 Read-only Data Model
161
162The custom model must reimplement the following methods to enable read-only
163access to the data from QML:
164
165\list
166\li \l{QAbstractItemModel::}{roleNames}() to expose the role names to the
167 QML frontend. For example, the following version returns the selected
168 table's field names as role names:
169 \code
170 QHash<int, QByteArray> SqlQueryModel::roleNames() const
171 {
172 QHash<int, QByteArray> roles;
173 // record() returns an empty QSqlRecord
174 for (int i = 0; i < this->record().count(); i ++) {
175 roles.insert(Qt::UserRole + i + 1, record().fieldName(i).toUtf8());
176 }
177 return roles;
178 }
179 \endcode
180\li \l{QSqlQueryModel::}{data}() to expose SQL data to the QML frontend.
181 For example, the following implementation returns data for the given
182 model index:
183 \code
184 QVariant SqlQueryModel::data(const QModelIndex &index, int role) const
185 {
186 QVariant value;
187
188 if (index.isValid()) {
189 if (role < Qt::UserRole) {
190 value = QSqlQueryModel::data(index, role);
191 } else {
192 int columnIdx = role - Qt::UserRole - 1;
193 QModelIndex modelIndex = this->index(index.row(), columnIdx);
194 value = QSqlQueryModel::data(modelIndex, Qt::DisplayRole);
195 }
196 }
197 return value;
198 }
199 \endcode
200\endlist
201
202The QSqlQueryModel class is good enough to implement a custom read-only
203model that represents data in an SQL database. The
204\l{Qt Quick Controls - Chat Tutorial}{chat tutorial} example
205demonstrates this very well by implementing a custom model to fetch the
206contact details from an SQLite database.
207
208\section3 Editable Data Model
209
210QSqlTableModel implements setData() as described \l{#changing-model-data}{below}.
211
212Depending on the \l{QSqlTableModel::}{EditStrategy} used by the model, the
213changes are either queued for submission later or submitted immediately.
214
215You can also insert new data into the model by calling
216\l {QSqlTableModel::insertRecord}(). In the following example snippet,
217a QSqlRecord is populated with book details and appended to the
218model:
219
220\code
221 ...
222 QSqlRecord newRecord = record();
223 newRecord.setValue("author", "John Grisham");
224 newRecord.setValue("booktitle", "The Litigators");
225 insertRecord(rowCount(), newRecord);
226 ...
227\endcode
228
229\section2 Exposing C++ Data Models to QML
230
231The above examples use required properties on the view to set
232model values directly in QML components. An alternative to this is to
233register the C++ model class as a QML type (see
234\l{Defining QML Types from C++}). This allows the model classes to be
235created directly as types within QML:
236
237\table
238\row
239
240\li C++
241\li
242\code
243class MyModel : public QAbstractItemModel
244{
245 Q_OBJECT
246 QML_ELEMENT
247
248 // [...]
249}
250\endcode
251\row
252\li QML
253\li
254\qml
255MyModel {
256 id: myModel
257}
258\endqml
259
260\qml
261ListView {
262 width: 200; height: 250
263 model: myModel
264 delegate: Text {
265 required property string someProperty
266 text: someProperty
267 }
268}
269\endqml
270
271\endtable
272
273See \l {Writing QML Extensions with C++} for details on writing QML types
274in C++.
275
276\section2 Changing Model Data
277
278Besides the \c roleNames() and \c data(), editable models must reimplement
279the \l{QAbstractItemModel::}{setData} method to save changes to existing model data.
280The following version of the method checks if the given model index is valid
281and the \c role is equal to \l Qt::EditRole:
282
283\code
284bool EditableModel::setData(const QModelIndex &index, const QVariant &value, int role)
285{
286 if (index.isValid() && role == Qt::EditRole) {
287 // Set data in model here. It can also be a good idea to check whether
288 // the new value actually differs from the current value
289 if (m_entries[index.row()] != value.toString()) {
290 m_entries[index.row()] = value.toString();
291 emit dataChanged(index, index, { Qt::EditRole, Qt::DisplayRole });
292 return true;
293 }
294 }
295 return false;
296}
297\endcode
298
299\note It is important to emit the \l{QAbstractItemModel::}{dataChanged}()
300signal after saving the changes.
301
302Unlike the C++ item views such as QListView or QTableView, the \c setData()
303method must be explicitly invoked from QML delegates whenever appropriate. This is done
304by simply assigning a new value to the corresponding model property.
305
306\qml
307ListView {
308 anchors.fill: parent
309 model: EditableModel {}
310 delegate: TextField {
311 width: ListView.view.width
312 text: model.edit
313 onAccepted: model.edit = text
314 }
315}
316\endqml
317
318\note The \c edit role is equal to \l Qt::EditRole. See \l{QAbstractItemModel::}{roleNames}()
319for the built-in role names. However, real life models would usually register custom roles.
320
321*/