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
|
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:FDL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Free Documentation License Usage
** 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. Please review the following information to ensure
** the GNU Free Documentation License version 1.3 requirements
** will be met: http://www.gnu.org/copyleft/fdl.html.
** $QT_END_LICENSE$
**
****************************************************************************/
/*!
\example itemviews/stardelegate
\title Star Delegate Example
\brief The Star Delegate example shows how to create a delegate that
can paint itself and that supports editing.
\image stardelegate.png The Star Delegate Example
When displaying data in a QListView, QTableView, or QTreeView,
the individual items are drawn by a
\l{Delegate Classes}{delegate}. Also, when the user starts
editing an item (e.g., by double-clicking the item), the delegate
provides an editor widget that is placed on top of the item while
editing takes place.
Delegates are subclasses of QAbstractItemDelegate. Qt provides
QStyledItemDelegate, which inherits QAbstractItemDelegate and
handles the most common data types (notably \c int and QString).
If we need to support custom data types, or want to customize the
rendering or the editing for existing data types, we can subclass
QAbstractItemDelegate or QStyledItemDelegate. See \l{Delegate
Classes} for more information about delegates, and \l{Model/View
Programming} if you need a high-level introduction to Qt's
model/view architecture (including delegates).
In this example, we will see how to implement a custom delegate
to render and edit a "star rating" data type, which can store
values such as "1 out of 5 stars".
The example consists of the following classes:
\list
\o \c StarRating is the custom data type. It stores a rating
expressed as stars, such as "2 out of 5 stars" or "5 out of
6 stars".
\o \c StarDelegate inherits QStyledItemDelegate and provides support
for \c StarRating (in addition to the data types already
handled by QStyledItemDelegate).
\o \c StarEditor inherits QWidget and is used by \c StarDelegate
to let the user edit a star rating using the mouse.
\endlist
To show the \c StarDelegate in action, we will fill a
QTableWidget with some data and install the delegate on it.
\section1 StarDelegate Class Definition
Here's the definition of the \c StarDelegate class:
\snippet examples/itemviews/stardelegate/stardelegate.h 0
All public functions are reimplemented virtual functions from
QStyledItemDelegate to provide custom rendering and editing.
\section1 StarDelegate Class Implementation
The \l{QAbstractItemDelegate::}{paint()} function is reimplemented
from QStyledItemDelegate and is called whenever the view needs to
repaint an item:
\snippet examples/itemviews/stardelegate/stardelegate.cpp 0
The function is invoked once for each item, represented by a
QModelIndex object from the model. If the data stored in the item
is a \c StarRating, we paint it ourselves; otherwise, we let
QStyledItemDelegate paint it for us. This ensures that the \c
StarDelegate can handle the most common data types.
In the case where the item is a \c StarRating, we draw the
background if the item is selected, and we draw the item using \c
StarRating::paint(), which we will review later.
\c{StartRating}s can be stored in a QVariant thanks to the
Q_DECLARE_METATYPE() macro appearing in \c starrating.h. More on
this later.
The \l{QAbstractItemDelegate::}{createEditor()} function is
called when the user starts editing an item:
\snippet examples/itemviews/stardelegate/stardelegate.cpp 2
If the item is a \c StarRating, we create a \c StarEditor and
connect its \c editingFinished() signal to our \c
commitAndCloseEditor() slot, so we can update the model when the
editor closes.
Here's the implementation of \c commitAndCloseEditor():
\snippet examples/itemviews/stardelegate/stardelegate.cpp 5
When the user is done editing, we emit
\l{QAbstractItemDelegate::}{commitData()} and
\l{QAbstractItemDelegate::}{closeEditor()} (both declared in
QAbstractItemDelegate), to tell the model that there is edited
data and to inform the view that the editor is no longer needed.
The \l{QAbstractItemDelegate::}{setEditorData()} function is
called when an editor is created to initialize it with data
from the model:
\snippet examples/itemviews/stardelegate/stardelegate.cpp 3
We simply call \c setStarRating() on the editor.
The \l{QAbstractItemDelegate::}{setModelData()} function is
called when editing is finished, to commit data from the editor
to the model:
\snippet examples/itemviews/stardelegate/stardelegate.cpp 4
The \c sizeHint() function returns an item's preferred size:
\snippet examples/itemviews/stardelegate/stardelegate.cpp 1
We simply forward the call to \c StarRating.
\section1 StarEditor Class Definition
The \c StarEditor class was used when implementing \c
StarDelegate. Here's the class definition:
\snippet examples/itemviews/stardelegate/stareditor.h 0
The class lets the user edit a \c StarRating by moving the mouse
over the editor. It emits the \c editingFinished() signal when
the user clicks on the editor.
The protected functions are reimplemented from QWidget to handle
mouse and paint events. The private function \c starAtPosition()
is a helper function that returns the number of the star under
the mouse pointer.
\section1 StarEditor Class Implementation
Let's start with the constructor:
\snippet examples/itemviews/stardelegate/stareditor.cpp 0
We enable \l{QWidget::setMouseTracking()}{mouse tracking} on the
widget so we can follow the cursor even when the user doesn't
hold down any mouse button. We also turn on QWidget's
\l{QWidget::autoFillBackground}{auto-fill background} feature to
obtain an opaque background. (Without the call, the view's
background would shine through the editor.)
The \l{QWidget::}{paintEvent()} function is reimplemented from
QWidget:
\snippet examples/itemviews/stardelegate/stareditor.cpp 1
We simply call \c StarRating::paint() to draw the stars, just
like we did when implementing \c StarDelegate.
\snippet examples/itemviews/stardelegate/stareditor.cpp 2
In the mouse event handler, we call \c setStarCount() on the
private data member \c myStarRating to reflect the current cursor
position, and we call QWidget::update() to force a repaint.
\snippet examples/itemviews/stardelegate/stareditor.cpp 3
When the user releases a mouse button, we simply emit the \c
editingFinished() signal.
\snippet examples/itemviews/stardelegate/stareditor.cpp 4
The \c starAtPosition() function uses basic linear algebra to
find out which star is under the cursor.
\section1 StarRating Class Definition
\snippet examples/itemviews/stardelegate/starrating.h 0
\codeline
\snippet examples/itemviews/stardelegate/starrating.h 1
The \c StarRating class represents a rating as a number of stars.
In addition to holding the data, it is also capable of painting
the stars on a QPaintDevice, which in this example is either a
view or an editor. The \c myStarCount member variable stores the
current rating, and \c myMaxStarCount stores the highest possible
rating (typically 5).
The Q_DECLARE_METATYPE() macro makes the type \c StarRating known
to QVariant, making it possible to store \c StarRating values in
QVariant.
\section1 StarRating Class Implementation
The constructor initializes \c myStarCount and \c myMaxStarCount,
and sets up the polygons used to draw stars and diamonds:
\snippet examples/itemviews/stardelegate/starrating.cpp 0
The \c paint() function paints the stars in this \c StarRating
object on a paint device:
\snippet examples/itemviews/stardelegate/starrating.cpp 2
We first set the pen and brush we will use for painting. The \c
mode parameter can be either \c Editable or \c ReadOnly. If \c
mode is editable, we use the \l{QPalette::}{Highlight} color
instead of the \l{QPalette::}{Foreground} color to draw the
stars.
Then we draw the stars. If we are in \c Edit mode, we paint
diamonds in place of stars if the rating is less than the highest
rating.
The \c sizeHint() function returns the preferred size for an area
to paint the stars on:
\snippet examples/itemviews/stardelegate/starrating.cpp 1
The preferred size is just enough to paint the maximum number of
stars. The function is called by both \c StarDelegate::sizeHint()
and \c StarEditor::sizeHint().
\section1 The \c main() Function
Here's the program's \c main() function:
\snippet examples/itemviews/stardelegate/main.cpp 5
The \c main() function creates a QTableWidget and sets a \c
StarDelegate on it. \l{QAbstractItemView::}{DoubleClicked} and
\l{QAbstractItemView::}{SelectedClicked} are set as
\l{QAbstractItemView::editTriggers()}{edit triggers}, so that the
editor is opened with a single click when the star rating item is
selected.
The \c populateTableWidget() function fills the QTableWidget with
data:
\snippet examples/itemviews/stardelegate/main.cpp 0
\snippet examples/itemviews/stardelegate/main.cpp 1
\dots
\snippet examples/itemviews/stardelegate/main.cpp 2
\snippet examples/itemviews/stardelegate/main.cpp 3
\codeline
\snippet examples/itemviews/stardelegate/main.cpp 4
Notice the call to qVariantFromValue to convert a \c
StarRating to a QVariant.
\section1 Possible Extensions and Suggestions
There are many ways to customize Qt's \l{Model/View
Programming}{model/view framework}. The approach used in this
example is appropriate for most custom delegates and editors.
Examples of possibilities not used by the star delegate and star
editor are:
\list
\o It is possible to open editors programmatically by calling
QAbstractItemView::edit(), instead of relying on edit
triggers. This could be use to support other edit triggers
than those offered by the QAbstractItemView::EditTrigger enum.
For example, in the Star Delegate example, hovering over an
item with the mouse might make sense as a way to pop up an
editor.
\o By reimplementing QAbstractItemDelegate::editorEvent(), it is
possible to implement the editor directly in the delegate,
instead of creating a separate QWidget subclass.
\endlist
*/
|