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
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
|
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** 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 widgets/tooltips
\title Tool Tips Example
\brief The Tool Tips example shows how to provide static and dynamic tool
tips for an application's widgets.
The simplest and most common way to set a widget's tool tip is by
calling its QWidget::setToolTip() function (static tool
tips). Then the tool tip is shown whenever the cursor points at
the widget. We show how to do this with our application's tool
buttons. But it is also possible to show different tool tips
depending on the cursor's position (dynamic tooltips). This
approach uses mouse tracking and event handling to determine what
widgets are located under the cursor at any point in time, and
displays their tool tips. The tool tips for the shape items in our
application are implemented using the latter approach.
\image tooltips-example.png
With the \c Tooltips application the user can create new shape
items with the provided tool buttons, and move the items around
using the mouse. Tooltips are provided whenever the cursor is
pointing to a shape item or one of the buttons.
The Tooltips example consists of two classes:
\list
\o \c ShapeItem is a custom widget representing one single shape item.
\o \c SortingBox inherits from QWidget and is the application's main
widget.
\endlist
First we will review the \c SortingBox class, then we will take a
look at the \c ShapeItem class.
\section1 SortingBox Class Definition
\snippet examples/widgets/tooltips/sortingbox.h 0
The \c SortingBox class inherits QWidget, and it is the Tooltips
application's main widget. We reimplement several of the event
handlers.
The \c event() function provides tooltips, the \c resize()
function makes sure the application appears consistently when the
user resizes the main widget, and the \c paintEvent() function
displays the shape items within the \c SortingBox widget. The
mouse event handlers are reimplemented to make the user able to
move the items around.
In addition we need three private slots to make the user able to
create new shape items.
\snippet examples/widgets/tooltips/sortingbox.h 1
We also create several private functions: We use the \c
initialItemPosition(), \c initialItemColor() and \c
createToolButton() functions when we are constructing the widget,
and we use the \c updateButtonGeometry() function whenever the
user is resizing the application's main widget.
The \c itemAt() function determines if there is a shape item at a
particular position, and the \c moveItemTo() function moves an
item to a new position. We use the \c createShapeItem(), \c
randomItemPosition() and \c randomItemColor() functions to create
new shape items.
\snippet examples/widgets/tooltips/sortingbox.h 2
We keep all the shape items in a QList, and we keep three
QPainterPath objects holding the shapes of a circle, a square and
a triangle. We also need to have a pointer to an item when it is
moving, and we need to know its previous position.
\section1 SortingBox Class Implementation
\snippet examples/widgets/tooltips/sortingbox.cpp 0
In the constructor, we first set the Qt::WA_StaticContents
attribute on the widget. This attribute indicates that the widget
contents are north-west aligned and static. On resize, such a
widget will receive paint events only for the newly visible part
of itself.
\snippet examples/widgets/tooltips/sortingbox.cpp 1
To be able to show the appropiate tooltips while the user is
moving the cursor around, we need to enable mouse tracking for the
widget.
If mouse tracking is disabled (the default), the widget only
receives mouse move events when at least one mouse button is
pressed while the mouse is being moved. If mouse tracking is
enabled, the widget receives mouse move events even if no buttons
are pressed.
\snippet examples/widgets/tooltips/sortingbox.cpp 2
A widget's background role defines the brush from the widget's
palette that is used to render the background, and QPalette::Base
is typically white.
\snippet examples/widgets/tooltips/sortingbox.cpp 3
After creating the application's tool buttons using the private \c
createToolButton() function, we construct the shapes of a circle,
a square and a triangle using QPainterPath.
The QPainterPath class provides a container for painting
operations, enabling graphical shapes to be constructed and
reused. The main advantage of painter paths over normal drawing
operations is that complex shapes only need to be created once,
but they can be drawn many times using only calls to
QPainter::drawPath().
\snippet examples/widgets/tooltips/sortingbox.cpp 4
Then we set the window title, resize the widget to a suitable
size, and finally create three initial shape items using the
private \c createShapeItem(), \c initialItemPosition() and \c
initialItemColor() functions.
\snippet examples/widgets/tooltips/sortingbox.cpp 5
QWidget::event() is the main event handler and receives all the
widget's events. Normally, we recommend reimplementing one of the
specialized event handlers instead of this function. But here we
want to catch the QEvent::ToolTip events, and since these are
rather rare, there exists no specific event handler. For that
reason we reimplement the main event handler, and the first thing
we need to do is to determine the event's type:
\snippet examples/widgets/tooltips/sortingbox.cpp 6
If the type is QEvent::ToolTip, we cast the event to a QHelpEvent,
otherwise we propagate the event using the QWidget::event()
function.
The QHelpEvent class provides an event that is used to request
helpful information about a particular point in a widget.
For example, the QHelpEvent::pos() function returns the event's
position relative to the widget to which the event is dispatched.
Here we use this information to determine if the position of the
event is contained within the area of any of the shape items. If
it is, we display the shape item's tooltip at the position of the
event. If not, we hide the tooltip and explicitly ignore the event.
This makes sure that the calling code does not start any tooltip
specific modes as a result of the event. Note that the
QToolTip::showText() function needs the event's position in global
coordinates provided by QHelpEvent::globalPos().
\snippet examples/widgets/tooltips/sortingbox.cpp 7
The \c resizeEvent() function is reimplemented to receive the
resize events dispatched to the widget. It makes sure that the
tool buttons keep their position relative to the main widget when
the widget is resized. We want the buttons to always be vertically
aligned in the application's bottom right corner, so each time the
main widget is resized we update the buttons geometry.
\snippet examples/widgets/tooltips/sortingbox.cpp 8
The \c paintEvent() function is reimplemented to receive paint
events for the widget. We create a QPainter for the \c SortingBox
widget, and run through the list of created shape items, drawing
each item at its defined position.
\snippet examples/widgets/tooltips/sortingbox.cpp 9
The painter will by default draw all the shape items at position
(0,0) in the \c SortingBox widget. The QPainter::translate()
function translates the coordinate system by the given offset,
making each shape item appear at its defined position. But
remember to translate the coordinate system back when the item is
drawn, otherwise the next shape item will appear at a position
relative to the item we drawed last.
\snippet examples/widgets/tooltips/sortingbox.cpp 10
The QPainter::setBrush() function sets the current brush used by
the painter. When the provided argument is a QColor, the function
calls the appropiate QBrush constructor which creates a brush with
the specified color and Qt::SolidPattern style. The
QPainter::drawPath() function draws the given path using the
current pen for outline and the current brush for filling.
\snippet examples/widgets/tooltips/sortingbox.cpp 11
The \c mousePressEvent() function is reimplemented to receive the
mouse press events dispatched to the widget. It determines if an
event's position is contained within the area of any of the shape
items, using the private \c itemAt() function.
If an item covers the position, we store a pointer to that item
and the event's position. If several of the shape items cover the
position, we store the pointer to the uppermost item. Finally, we
move the shape item to the end of the list, and make a call to the
QWidget::update() function to make the item appear on top.
The QWidget::update() function does not cause an immediate
repaint; instead it schedules a paint event for processing when Qt
returns to the main event loop.
\snippet examples/widgets/tooltips/sortingbox.cpp 12
The \c mouseMoveEvent() function is reimplemented to receive mouse
move events for the widget. If the left mouse button is pressed
and there exists a shape item in motion, we use the private \c
moveItemTo() function to move the item with an offset
corresponding to the offset between the positions of the current
mouse event and the previous one.
\snippet examples/widgets/tooltips/sortingbox.cpp 13
The \c mouseReleaseEvent() function is reimplemented to receive
the mouse release events dispatched to the widget. If the left
mouse button is pressed and there exists a shape item in motion,
we use the private \c moveItemTo() function to move the item like
we did in \c mouseMoveEvent(). But then we remove the pointer to
the item in motion, making the shape item's position final for
now. To move the item further, the user will need to press the
left mouse button again.
\snippet examples/widgets/tooltips/sortingbox.cpp 14
\codeline
\snippet examples/widgets/tooltips/sortingbox.cpp 15
\codeline
\snippet examples/widgets/tooltips/sortingbox.cpp 16
The \c createNewCircle(), \c createNewSquare() and \c
createNewTriangle() slots simply create new shape items, using the
private \c createShapeItem(), \c randomItemPosition() and \c
randomItemColor() functions.
\snippet examples/widgets/tooltips/sortingbox.cpp 17
In the \c itemAt() function, we run through the list of created
shape items to check if the given position is contained within the
area of any of the shape items.
For each shape item we use the QPainterPath::contains() function
to find out if the item's painter path contains the position. If
it does we return the index of the item, otherwise we return
-1. We run through the list backwards to get the index of the
uppermost shape item in case several items cover the position.
\snippet examples/widgets/tooltips/sortingbox.cpp 18
The \c moveItemTo() function moves the shape item in motion, and
the parameter \c pos is the position of a mouse event. First we
calculate the offset between the parameter \c pos and the previous
mouse event position. Then we add the offset to the current
position of the item in motion.
It is tempting to simply set the position of the item to be the
parameter \c pos. But an item's position defines the top left
corner of the item's bounding rectangle, and the parameter \c pos
can be any point; The suggested shortcut would cause the item to
jump to a position where the cursor is pointing to the bounding
rectangle's top left corner, regardless of the item's previous
position.
\snippet examples/widgets/tooltips/sortingbox.cpp 19
Finally, we update the previous mouse event position, and make a
call to the QWidget::update() function to make the item appear at
its new position.
\snippet examples/widgets/tooltips/sortingbox.cpp 20
In the \c updateButtonGeometry() function we set the geometry for
the given button. The parameter coordinates define the bottom
right corner of the button. We use these coordinates and the
button's size hint to determine the position of the upper left
corner. This position, and the button's width and height, are the
arguments required by the QWidget::setGeometry() function.
In the end, we calculate and return the y-coordinate of the bottom
right corner of the next button. We use the QWidget::style()
function to retrieve the widget's GUI style, and then
QStyle::pixelMetric() to determine the widget's preferred default
spacing between its child widgets.
\snippet examples/widgets/tooltips/sortingbox.cpp 21
The \c createShapeItem() function creates a single shape item. It
sets the path, tooltip, position and color, using the item's own
functions. In the end, the function appends the new item to the
list of shape items, and calls the QWidget::update() function to
make it appear with the other items within the \c SortingBox
widget.
\snippet examples/widgets/tooltips/sortingbox.cpp 22
The \c createToolButton() function is called from the \c
SortingBox constructor. We create a tool button with the given
tooltip and icon. The button's parent is the \c SortingBox widget,
and its size is 32 x 32 pixels. Before we return the button, we
connect it to the given slot.
\snippet examples/widgets/tooltips/sortingbox.cpp 23
The \c initialItemPosition() function is also called from the
constructor. We want the three first items to initially be
centered in the middle of the \c SortingBox widget, and we use
this function to calculate their positions.
\snippet examples/widgets/tooltips/sortingbox.cpp 24
Whenever the user creates a new shape item, we want the new item
to appear at a random position, and we use the \c
randomItemPosition() function to calculate such a position. We
make sure that the item appears within the visible area of the
\c SortingBox widget, using the widget's current width and heigth
when calculating the random coordinates.
\snippet examples/widgets/tooltips/sortingbox.cpp 25
As with \c initialItemPosition(), the \c initialItemColor()
function is called from the constructor. The purposes of both
functions are purely cosmetic: We want to control the inital
position and color of the three first items.
\snippet examples/widgets/tooltips/sortingbox.cpp 26
Finally the \c randomItemColor() function is implemented to give
the shape items the user creates, a random color.
\section1 ShapeItem Class Definition
\snippet examples/widgets/tooltips/shapeitem.h 0
The \c ShapeItem class is a custom widget representing one single
shape item. The widget has a path, a position, a color and a
tooltip. We need functions to set or modify these objects, as well
as functions that return them. We make the latter functions \c
const to prohibit any modifications of the objects,
i.e. prohibiting unauthorized manipulation of the shape items
appearance.
\section1 ShapeItem Class Implementation
\snippet examples/widgets/tooltips/shapeitem.cpp 0
\codeline
\snippet examples/widgets/tooltips/shapeitem.cpp 1
\codeline
\snippet examples/widgets/tooltips/shapeitem.cpp 2
\codeline
\snippet examples/widgets/tooltips/shapeitem.cpp 3
This first group of functions simply return the objects that are
requested. The objects are returned as constants, i.e. they cannot
be modified.
\snippet examples/widgets/tooltips/shapeitem.cpp 4
\codeline
\snippet examples/widgets/tooltips/shapeitem.cpp 5
\codeline
\snippet examples/widgets/tooltips/shapeitem.cpp 6
\codeline
\snippet examples/widgets/tooltips/shapeitem.cpp 7
The last group of functions set or modify the shape item's path,
position, color and tooltip, respectively.
*/
|