1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
|
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:FDL$
** GNU Free Documentation License
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of
** this file.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms
** and conditions contained in a signed written agreement between you
** and Nokia.
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
/*!
\example itemviews/simpletreemodel
\title Simple Tree Model Example
The Simple Tree Model example shows how to create a basic, read-only
hierarchical model to use with Qt's standard view classes. For a
description of simple non-hierarchical list and table models, see the
\l{Model/View Programming} overview.
\image simpletreemodel-example.png
Qt's model/view architecture provides a standard way for views to
manipulate information in a data source, using an abstract model
of the data to simplify and standardize the way it is accessed.
Simple models represent data as a table of items, and allow views
to access this data via an
\l{Model/View Programming#Models}{index-based} system. More generally,
models can be used to represent data in the form of a tree structure
by allowing each item to act as a parent to a table of child items.
Before attempting to implement a tree model, it is worth considering whether
the data is supplied by an external source, or whether it is going to be
maintained within the model itself. In this example, we will implement an
internal structure to hold data rather than discuss how to package data from
an external source.
\section1 Design and Concepts
The data structure that we use to represent the structure of the data takes
the form of a tree built from \c TreeItem objects. Each \c TreeItem
represents an item in a tree view, and contains several columns of data.
\target SimpleTreeModelStructure
\table
\row \i \inlineimage treemodel-structure.png
\i \bold{Simple Tree Model Structure}
The data is stored internally in the model using \c TreeItem objects that
are linked together in a pointer-based tree structure. Generally, each
\c TreeItem has a parent item, and can have a number of child items.
However, the root item in the tree structure has no parent item and it
is never referenced outside the model.
Each \c TreeItem contains information about its place in the tree
structure; it can return its parent item and its row number. Having
this information readily available makes implementing the model easier.
Since each item in a tree view usually contains several columns of data
(a title and a summary in this example), it is natural to store this
information in each item. For simplicity, we will use a list of QVariant
objects to store the data for each column in the item.
\endtable
The use of a pointer-based tree structure means that, when passing a
model index to a view, we can record the address of the corresponding
item in the index (see QAbstractItemModel::createIndex()) and retrieve
it later with QModelIndex::internalPointer(). This makes writing the
model easier and ensures that all model indexes that refer to the same
item have the same internal data pointer.
With the appropriate data structure in place, we can create a tree model
with a minimal amount of extra code to supply model indexes and data to
other components.
\section1 TreeItem Class Definition
The \c TreeItem class is defined as follows:
\snippet examples/itemviews/simpletreemodel/treeitem.h 0
The class is a basic C++ class. It does not inherit from QObject or
provide signals and slots. It is used to hold a list of QVariants,
containing column data, and information about its position in the tree
structure. The functions provide the following features:
\list
\o The \c appendChildItem() is used to add data when the model is first
constructed and is not used during normal use.
\o The \c child() and \c childCount() functions allow the model to obtain
information about any child items.
\o Information about the number of columns associated with the item is
provided by \c columnCount(), and the data in each column can be
obtained with the data() function.
\o The \c row() and \c parent() functions are used to obtain the item's
row number and parent item.
\endlist
The parent item and column data are stored in the \c parentItem and
\c itemData private member variables. The \c childItems variable contains
a list of pointers to the item's own child items.
\section1 TreeItem Class Implementation
The constructor is only used to record the item's parent and the data
associated with each column.
\snippet examples/itemviews/simpletreemodel/treeitem.cpp 0
A pointer to each of the child items belonging to this item will be
stored in the \c childItems private member variable. When the class's
destructor is called, it must delete each of these to ensure that
their memory is reused:
\snippet examples/itemviews/simpletreemodel/treeitem.cpp 1
Since each of the child items are constructed when the model is initially
populated with data, the function to add child items is straightforward:
\snippet examples/itemviews/simpletreemodel/treeitem.cpp 2
Each item is able to return any of its child items when given a suitable
row number. For example, in the \l{#SimpleTreeModelStructure}{above diagram},
the item marked with the letter "A" corresponds to the child of the root item
with \c{row = 0}, the "B" item is a child of the "A" item with \c{row = 1},
and the "C" item is a child of the root item with \c{row = 1}.
The \c child() function returns the child that corresponds to
the specified row number in the item's list of child items:
\snippet examples/itemviews/simpletreemodel/treeitem.cpp 3
The number of child items held can be found with \c childCount():
\snippet examples/itemviews/simpletreemodel/treeitem.cpp 4
The \c TreeModel uses this function to determine the number of rows that
exist for a given parent item.
The \c row() function reports the item's location within its parent's
list of items:
\snippet examples/itemviews/simpletreemodel/treeitem.cpp 8
Note that, although the root item (with no parent item) is automatically
assigned a row number of 0, this information is never used by the model.
The number of columns of data in the item is trivially returned by the
\c columnCount() function.
\snippet examples/itemviews/simpletreemodel/treeitem.cpp 5
Column data is returned by the \c data() function, taking advantage of
QList's ability to provide sensible default values if the column number
is out of range:
\snippet examples/itemviews/simpletreemodel/treeitem.cpp 6
The item's parent is found with \c parent():
\snippet examples/itemviews/simpletreemodel/treeitem.cpp 7
Note that, since the root item in the model will not have a parent, this
function will return zero in that case. We need to ensure that the model
handles this case correctly when we implement the \c TreeModel::parent()
function.
\section1 TreeModel Class Definition
The \c TreeModel class is defined as follows:
\snippet examples/itemviews/simpletreemodel/treemodel.h 0
This class is similar to most other subclasses of QAbstractItemModel that
provide read-only models. Only the form of the constructor and the
\c setupModelData() function are specific to this model. In addition, we
provide a destructor to clean up when the model is destroyed.
\section1 TreeModel Class Implementation
For simplicity, the model does not allow its data to be edited. As a
result, the constructor takes an argument containing the data that the
model will share with views and delegates:
\snippet examples/itemviews/simpletreemodel/treemodel.cpp 0
It is up to the constructor to create a root item for the model. This
item only contains vertical header data for convenience. We also use it
to reference the internal data structure that contains the model data,
and it is used to represent an imaginary parent of top-level items in
the model.
The model's internal data structure is populated with items by the
\c setupModelData() function. We will examine this function separately
at the end of this document.
The destructor ensures that the root item and all of its descendants
are deleted when the model is destroyed:
\snippet examples/itemviews/simpletreemodel/treemodel.cpp 1
Since we cannot add data to the model after it is constructed and set
up, this simplifies the way that the internal tree of items is managed.
Models must implement an \c index() function to provide indexes for
views and delegates to use when accessing data. Indexes are created
for other components when they are referenced by their row and column
numbers, and their parent model index. If an invalid model
index is specified as the parent, it is up to the model to return an
index that corresponds to a top-level item in the model.
When supplied with a model index, we first check whether it is valid.
If it is not, we assume that a top-level item is being referred to;
otherwise, we obtain the data pointer from the model index with its
\l{QModelIndex::internalPointer()}{internalPointer()} function and use
it to reference a \c TreeItem object. Note that all the model indexes
that we construct will contain a pointer to an existing \c TreeItem,
so we can guarantee that any valid model indexes that we receive will
contain a valid data pointer.
\snippet examples/itemviews/simpletreemodel/treemodel.cpp 6
Since the row and column arguments to this function refer to a
child item of the corresponding parent item, we obtain the item using
the \c TreeItem::child() function. The
\l{QAbstractItemModel::createIndex()}{createIndex()} function is used
to create a model index to be returned. We specify the row and column
numbers, and a pointer to the item itself. The model index can be used
later to obtain the item's data.
The way that the \c TreeItem objects are defined makes writing the
\c parent() function easy:
\snippet examples/itemviews/simpletreemodel/treemodel.cpp 7
We only need to ensure that we never return a model index corresponding
to the root item. To be consistent with the way that the \c index()
function is implemented, we return an invalid model index for the
parent of any top-level items in the model.
When creating a model index to return, we must specify the row and
column numbers of the parent item within its own parent. We can
easily discover the row number with the \c TreeItem::row() function,
but we follow a convention of specifying 0 as the column number of
the parent. The model index is created with
\l{QAbstractItemModel::createIndex()}{createIndex()} in the same way
as in the \c index() function.
The \c rowCount() function simply returns the number of child items
for the \c TreeItem that corresponds to a given model index, or the
number of top-level items if an invalid index is specified:
\snippet examples/itemviews/simpletreemodel/treemodel.cpp 8
Since each item manages its own column data, the \c columnCount()
function has to call the item's own \c columnCount() function to
determine how many columns are present for a given model index.
As with the \c rowCount() function, if an invalid model index is
specified, the number of columns returned is determined from the
root item:
\snippet examples/itemviews/simpletreemodel/treemodel.cpp 2
Data is obtained from the model via \c data(). Since the item manages
its own columns, we need to use the column number to retrieve the data
with the \c TreeItem::data() function:
\snippet examples/itemviews/simpletreemodel/treemodel.cpp 3
Note that we only support the \l{Qt::ItemDataRole}{DisplayRole}
in this implementation, and we also return invalid QVariant objects for
invalid model indexes.
We use the \c flags() function to ensure that views know that the
model is read-only:
\snippet examples/itemviews/simpletreemodel/treemodel.cpp 4
The \c headerData() function returns data that we conveniently stored
in the root item:
\snippet examples/itemviews/simpletreemodel/treemodel.cpp 5
This information could have been supplied in a different way: either
specified in the constructor, or hard coded into the \c headerData()
function.
\section1 Setting Up the Data in the Model
We use the \c setupModelData() function to set up the initial data in
the model. This function parses a text file, extracting strings of
text to use in the model, and creates item objects that record both
the data and the overall model structure.
Naturally, this function works in a way that is very specific to
this model. We provide the following description of its behavior,
and refer the reader to the example code itself for more information.
We begin with a text file in the following format:
\snippet doc/src/snippets/code/doc_src_examples_simpletreemodel.qdoc 0
\dots
\snippet doc/src/snippets/code/doc_src_examples_simpletreemodel.qdoc 1
We process the text file with the following two rules:
\list
\o For each pair of strings on each line, create an item (or node)
in a tree structure, and place each string in a column of data
in the item.
\o When the first string on a line is indented with respect to the
first string on the previous line, make the item a child of the
previous item created.
\endlist
To ensure that the model works correctly, it is only necessary to
create instances of \c TreeItem with the correct data and parent item.
*/
|