/****************************************************************************+ −
**+ −
** Copyright (C) 2009 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:LGPL$+ −
** No Commercial Usage+ −
** This file contains pre-release code and may not be distributed.+ −
** You may use this file in accordance with the terms and conditions+ −
** contained in the Technology Preview License Agreement accompanying+ −
** this package.+ −
**+ −
** GNU Lesser General Public License Usage+ −
** Alternatively, this file may be used under the terms of the GNU Lesser+ −
** General Public License version 2.1 as published by the Free Software+ −
** Foundation and appearing in the file LICENSE.LGPL included in the+ −
** packaging of this file. Please review the following information to+ −
** ensure the GNU Lesser General Public License version 2.1 requirements+ −
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.+ −
**+ −
** In addition, as a special exception, Nokia gives you certain additional+ −
** rights. These rights are described in the Nokia Qt LGPL Exception+ −
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.+ −
**+ −
** If you have questions regarding the use of this file, please contact+ −
** Nokia at qt-info@nokia.com.+ −
**+ −
**+ −
**+ −
**+ −
**+ −
**+ −
**+ −
**+ −
** $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+ −
\o The \c MainWindow class inherits QMainWindow and creates+ −
the examples menus and connect their slots and signals.+ −
\o The \c TabletCanvas class inherits QWidget and + −
receives tablet events. It uses the events to paint on a+ −
QImage, which it draws onto itself.+ −
\o The \c TabletApplication class inherits QApplication. This+ −
class handles tablet events that are not sent to \c tabletEvent(). + −
We will look at this later.+ −
\o 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 examples/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 examples/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 examples/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 examples/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 examples/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 examples/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 examples/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 examples/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 examples/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 examples/widgets/tablet/mainwindow.cpp 8+ −
\dots+ −
\snippet examples/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 examples/widgets/tablet/mainwindow.cpp 10+ −
+ −
Here is the implementation of \c createMenus():+ −
+ −
\snippet examples/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 examples/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 QImage with \c myPen and \c myBrush using \c+ −
myColor. The \c saveImage() and \c loadImage() saves and loads+ −
the QImage to disk. The image 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 paintImage(), \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 examples/widgets/tablet/tabletcanvas.cpp 0+ −
+ −
In the constructor we initialize our class variables. We need+ −
to draw the background of our image, as the default is gray.+ −
+ −
Here is the implementation of \c saveImage():+ −
+ −
\snippet examples/widgets/tablet/tabletcanvas.cpp 1+ −
+ −
QImage implements functionality to save itself to disk, so we+ −
simply call \l{QImage::}{save()}.+ −
+ −
Here is the implementation of \c loadImage():+ −
+ −
\snippet examples/widgets/tablet/tabletcanvas.cpp 2+ −
+ −
We simply call \l{QImage::}{load()}, which loads the image in \a+ −
file.+ −
+ −
Here is the implementation of \c tabletEvent():+ −
+ −
\snippet examples/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 paintImage() 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 examples/widgets/tablet/tabletcanvas.cpp 4+ −
+ −
We simply draw the image to the top left of the widget.+ −
+ −
Here is the implementation of \c paintImage():+ −
+ −
\snippet examples/widgets/tablet/tabletcanvas.cpp 5+ −
+ −
In this function we draw on the image 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 examples/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 examples/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 examples/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 examples/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 examples/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 examples/widgets/tablet/tabletcanvas.cpp 11+ −
+ −
We finally check wether the pointer is the stylus or the eraser.+ −
If it is the eraser, we set the color to the background color of+ −
the image 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 examples/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 examples/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 examples/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.+ −
*/+ −