blob: 35e3b1e29fe590d057cb0d720fc6773375de9766 [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://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 https://www.qt.io/terms-conditions. For further
** information use the contact form at https://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: https://www.gnu.org/licenses/fdl-1.3.html.
** $QT_END_LICENSE$
**
****************************************************************************/
/*!
\example widgets/tooltips
\title Tool Tips Example
\ingroup examples-widgets
\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
\li \c ShapeItem is a custom widget representing one single shape item.
\li \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 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 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 widgets/tooltips/sortingbox.h 2
We keep all the shape items in a QVector, 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 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 widgets/tooltips/sortingbox.cpp 1
To be able to show the appropriate 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 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 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 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 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 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 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 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 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 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 appropriate 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 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 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 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 widgets/tooltips/sortingbox.cpp 14
\codeline
\snippet widgets/tooltips/sortingbox.cpp 15
\codeline
\snippet 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 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 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 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 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 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 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 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 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 height
when calculating the random coordinates.
\snippet 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 initial
position and color of the three first items.
\snippet 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 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 widgets/tooltips/shapeitem.cpp 0
\codeline
\snippet widgets/tooltips/shapeitem.cpp 1
\codeline
\snippet widgets/tooltips/shapeitem.cpp 2
\codeline
\snippet 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 widgets/tooltips/shapeitem.cpp 4
\codeline
\snippet widgets/tooltips/shapeitem.cpp 5
\codeline
\snippet widgets/tooltips/shapeitem.cpp 6
\codeline
\snippet widgets/tooltips/shapeitem.cpp 7
The last group of functions set or modify the shape item's path,
position, color and tooltip, respectively.
*/