qt5base-lts/examples/widgets/doc/tablet.qdoc
Frederik Gladhorn 3ef3c662fe Don't reference widgets/widgets in example doc.
Change-Id: Ie1fe516f75ca8c1b2233dc6bb2b887b55593e730
Reviewed-by: Martin Smith <martin.smith@nokia.com>
2012-09-01 11:24:50 +02:00

370 lines
14 KiB
Plaintext

/****************************************************************************
**
** 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/tablet
\title Tablet Example
This example shows how to use a Wacom tablet in Qt applications.
\image tabletexample.png
When you use a tablet with Qt applications, \l{QTabletEvent}s are
generated. You need to reimplement the
\l{QWidget::}{tabletEvent()} event handler if you want to handle
tablet events. Events are generated when the device used for
drawing enters and leaves the proximity of the tablet (i.e., when
it is close but not pressed down on it), when a device is pushed
down and released from it, and when a device is moved on the
tablet.
The information available in QTabletEvent depends on the device
used. The tablet in this example has two different devices for
drawing: a stylus and an airbrush. For both devices the event
contains the position of the device, pressure on the tablet,
vertical tilt, and horizontal tilt (i.e, the angle between the
device and the perpendicular of the tablet). The airbrush has a
finger wheel; the position of this is also available in the tablet
event.
In this example we implement a drawing program. You can use the
stylus to draw on the tablet as you use a pencil on paper. When
you draw with the airbrush you get a spray of paint; the finger
wheel is used to change the density of the spray. The pressure and
tilt can change the alpha and saturation values of the QColor and the
width of the QPen used for drawing.
The example consists of the following:
\list
\li The \c MainWindow class inherits QMainWindow and creates
the examples menus and connect their slots and signals.
\li The \c TabletCanvas class inherits QWidget and
receives tablet events. It uses the events to paint on a
offscreen pixmap, which it draws onto itself.
\li The \c TabletApplication class inherits QApplication. This
class handles tablet events that are not sent to \c tabletEvent().
We will look at this later.
\li The \c main() function creates a \c MainWindow and shows it
as a top level window.
\endlist
\section1 MainWindow Class Definition
The \c MainWindow creates a \c TabletCanvas and sets it as its
center widget.
\snippet widgets/tablet/mainwindow.h 0
The QActions let the user select if the tablets pressure and
tilt should change the pen width, color alpha component and color
saturation. \c createActions() creates all actions, and \c
createMenus() sets up the menus with the actions. We have one
QActionGroup for the actions that alter the alpha channel, color
saturation and line width respectively. The action groups are
connected to the \c alphaActionTriggered(), \c
colorSaturationActiontriggered(), and \c
lineWidthActionTriggered() slots, which calls functions in \c
myCanvas.
\section1 MainWindow Class Implementation
We start width a look at the constructor \c MainWindow():
\snippet widgets/tablet/mainwindow.cpp 0
In the constructor we create the canvas, actions, and menus.
We set the canvas as the center widget. We also initialize the
canvas to match the state of our menus and start drawing with a
red color.
Here is the implementation of \c brushColorAct():
\snippet widgets/tablet/mainwindow.cpp 1
We let the user pick a color with a QColorDialog. If it is valid,
we set a new drawing color with \c setColor().
Here is the implementation of \c alphaActionTriggered():
\snippet widgets/tablet/mainwindow.cpp 2
The \c TabletCanvas class supports two ways by which the alpha
channel of the drawing color can be changed: tablet pressure and
tilt. We have one action for each and an action if the alpha
channel should not be changed.
Here is the implementation of \c lineWidthActionTriggered():
\snippet widgets/tablet/mainwindow.cpp 3
We check which action is selected in \c lineWidthGroup, and set
how the canvas should change the drawing line width.
Here is the implementation of \c saturationActionTriggered():
\snippet widgets/tablet/mainwindow.cpp 4
We check which action is selected in \c colorSaturationGroup, and
set how the canvas should change the color saturation of the
drawing color.
Here is the implementation of \c saveAct():
\snippet widgets/tablet/mainwindow.cpp 5
We use the QFileDialog to let the user select a file to save the
drawing in. It is the \c TabletCanvas that save the drawing, so we
call its \c saveImage() function.
Here is the implementation of \c loadAct():
\snippet widgets/tablet/mainwindow.cpp 6
We let the user select the image file to be opened with
a QFileDialog; we then ask the canvas to load the image with \c
loadImage().
Here is the implementation of \c aboutAct():
\snippet widgets/tablet/mainwindow.cpp 7
We show a message box with a short description of the example.
\c createActions() creates all actions and action groups of
the example. We look at the creation of one action group and its
actions. See the \l{Application Example}{application example} if
you want a high-level introduction to QActions.
Here is the implementation of \c createActions:
\snippet widgets/tablet/mainwindow.cpp 8
\dots
\snippet widgets/tablet/mainwindow.cpp 9
We want the user to be able to choose if the drawing color's
alpha component should be changed by the tablet pressure or tilt.
We have one action for each choice and an action if the alpha
channel is not to be changed, i.e, the color is opaque. We make
the actions checkable; the \c alphaChannelGroup will then ensure
that only one of the actions are checked at any time. The \c
triggered() signal is emitted when an action is checked.
\dots
\snippet widgets/tablet/mainwindow.cpp 10
Here is the implementation of \c createMenus():
\snippet widgets/tablet/mainwindow.cpp 11
We create the menus of the example and add the actions to them.
\section1 TabletCanvas Class Definition
The \c TabletCanvas class provides a surface on which the
user can draw with a tablet.
\snippet widgets/tablet/tabletcanvas.h 0
The canvas can change the alpha channel, color saturation,
and line width of the drawing. We have one enum for each of
these; their values decide if it is the tablet pressure or tilt
that will alter them. We keep a private variable for each, the \c
alphaChannelType, \c colorSturationType, and \c penWidthType,
which we provide access functions for.
We draw on a QPixmap with \c myPen and \c myBrush using \c
myColor. The \c saveImage() and \c loadImage() saves and loads
the QPixmap to disk. The pixmap is drawn on the widget in \c
paintEvent(). The \c pointerType and \c deviceType keeps the type
of pointer, which is either a pen or an eraser, and device
currently used on the tablet, which is either a stylus or an
airbrush.
The interpretation of events from the tablet is done in \c
tabletEvent(); \c paintPixmap(), \c updateBrush(), and \c
brushPattern() are helper functions used by \c tabletEvent().
\section1 TabletCanvas Class Implementation
We start with a look at the constructor:
\snippet widgets/tablet/tabletcanvas.cpp 0
In the constructor we initialize our class variables. We need
to draw the background of our pixmap, as the default is gray.
Here is the implementation of \c saveImage():
\snippet widgets/tablet/tabletcanvas.cpp 1
QPixmap implements functionality to save itself to disk, so we
simply call \l{QPixmap::}{save()}.
Here is the implementation of \c loadImage():
\snippet widgets/tablet/tabletcanvas.cpp 2
We simply call \l{QPixmap::}{load()}, which loads the image in \a
file.
Here is the implementation of \c tabletEvent():
\snippet widgets/tablet/tabletcanvas.cpp 3
We get three kind of events to this function: TabletPress,
TabletRelease, and TabletMove, which is generated when a device
is pressed down on, leaves, or moves on the tablet. We set the \c
deviceDown to true when a device is pressed down on the tablet;
we then know when we should draw when we receive move events. We
have implemented the \c updateBrush() and \c paintPixmap() helper
functions to update \c myBrush and \c myPen after the state of \c
alphaChannelType, \c colorSaturationType, and \c lineWidthType.
Here is the implementation of \c paintEvent():
\snippet widgets/tablet/tabletcanvas.cpp 4
We simply draw the pixmap to the top left of the widget.
Here is the implementation of \c paintPixmap():
\snippet widgets/tablet/tabletcanvas.cpp 5
In this function we draw on the pixmap based on the movement of the
device. If the device used on the tablet is a stylus we want to draw a
line between the positions of the stylus recorded in \c polyLine. We
also assume that this is a reasonable handling of any unknown device,
but update the statusbar with a warning so that the user can see that
for his tablet he might have to implement special handling.
If it is an airbrush we want to draw a circle of points with a
point density based on the tangential pressure, which is the position
of the finger wheel on the airbrush. We use the Qt::BrushStyle to
draw the points as it has styles that draw points with different
density; we select the style based on the tangential pressure in
\c brushPattern().
\snippet widgets/tablet/tabletcanvas.cpp 6
We return a brush style with a point density that increases with
the tangential pressure.
In \c updateBrush() we set the pen and brush used for drawing
to match \c alphaChannelType, \c lineWidthType, \c
colorSaturationType, and \c myColor. We will examine the code to
set up \c myBrush and \c myPen for each of these variables:
\snippet widgets/tablet/tabletcanvas.cpp 7
We fetch the current drawingcolor's hue, saturation, value,
and alpha values. \c hValue and \c vValue are set to the
horizontal and vertical tilt as a number from 0 to 255. The
original values are in degrees from -60 to 60, i.e., 0 equals
-60, 127 equals 0, and 255 equals 60 degrees. The angle measured
is between the device and the perpendicular of the tablet (see
QTabletEvent for an illustration).
\snippet widgets/tablet/tabletcanvas.cpp 8
The alpha channel of QColor is given as a number between 0
and 255 where 0 is transparent and 255 is opaque.
\l{QTabletEvent::}{pressure()} returns the pressure as a qreal
between 0.0 and 1.0. By subtracting 127 from the tilt values and
taking the absolute value we get the smallest alpha values (i.e.,
the color is most transparent) when the pen is perpendicular to
the tablet. We select the largest of the vertical and horizontal
tilt value.
\snippet widgets/tablet/tabletcanvas.cpp 9
The colorsaturation is given as a number between 0 and 255. It is
set with \l{QColor::}{setHsv()}. We can set the tilt values
directly, but must multiply the pressure to a number between 0 and
255.
\snippet widgets/tablet/tabletcanvas.cpp 10
The width of the pen increases with the pressure. When the pen
width is controlled with the tilt we let the width increse with
the angle between the device and the perpendicular of the tablet.
\snippet widgets/tablet/tabletcanvas.cpp 11
We finally check whether the pointer is the stylus or the eraser.
If it is the eraser, we set the color to the background color of
the pixmap an let the pressure decide the pen width, else we set
the colors we have set up previously in the function.
\section1 TabletApplication Class Definition
We inherit QApplication in this class because we want to
reimplement the \l{QApplication::}{event()} function.
\snippet widgets/tablet/tabletapplication.h 0
We keep a \c TabletCanvas we send the device type of the events we
handle in the \c event() function to. The TabletEnterProximity
and TabletLeaveProximity events are not sendt to the QApplication
object, while other tablet events are sendt to the QWidget's
\c event(), which sends them on to \l{QWidget::}{tabletEvent()}.
Since we want to handle these events we have implemented \c
TabletApplication.
\section1 TabletApplication Class Implementation
Here is the implementation of \c event():
\snippet widgets/tablet/tabletapplication.cpp 0
We use this function to handle the TabletEnterProximity and
TabletLeaveProximity events, which is generated when a device
enters and leaves the proximity of the tablet. The intended use of these
events is to do work that is dependent on what kind of device is
used on the tablet. This way, you don't have to do this work
when other events are generated, which is more frequently than the
leave and enter proximity events. We call \c setTabletDevice() in
\c TabletCanvas.
\section1 The \c main() function
Here is the examples \c main() function:
\snippet widgets/tablet/main.cpp 0
In the \c main() function we create a \c MainWinow and display it
as a top level window. We use the \c TabletApplication class. We
need to set the canvas after the application is created. We cannot
use classes that implement event handling before an QApplication
object is instantiated.
*/