1 /****************************************************************************
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
6 ** This file is part of the documentation of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:FDL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
17 ** GNU Free Documentation License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Free
19 ** Documentation License version 1.3 as published by the Free Software
20 ** Foundation and appearing in the file included in the packaging of
21 ** this file. Please review the following information to ensure
22 ** the GNU Free Documentation License version 1.3 requirements
23 ** will be met: http://www.gnu.org/copyleft/fdl.html.
26 ****************************************************************************/
29 \example widgets/tablet
32 \brief The Tablet example shows how to use a Wacom tablet in Qt applications.
34 \image tabletexample.png
36 When you use a tablet with Qt applications, \l{QTabletEvent}s are
37 generated. You need to reimplement the
38 \l{QWidget::}{tabletEvent()} event handler if you want to handle
39 tablet events. Events are generated when the device used for
40 drawing enters and leaves the proximity of the tablet (i.e., when
41 it is close but not pressed down on it), when a device is pushed
42 down and released from it, and when a device is moved on the
45 The information available in QTabletEvent depends on the device
46 used. The tablet in this example has two different devices for
47 drawing: a stylus and an airbrush. For both devices the event
48 contains the position of the device, pressure on the tablet,
49 vertical tilt, and horizontal tilt (i.e, the angle between the
50 device and the perpendicular of the tablet). The airbrush has a
51 finger wheel; the position of this is also available in the tablet
54 In this example we implement a drawing program. You can use the
55 stylus to draw on the tablet as you use a pencil on paper. When
56 you draw with the airbrush you get a spray of paint; the finger
57 wheel is used to change the density of the spray. The pressure and
58 tilt can change the alpha and saturation values of the QColor and the
59 width of the QPen used for drawing.
61 The example consists of the following:
64 \o The \c MainWindow class inherits QMainWindow and creates
65 the examples menus and connect their slots and signals.
66 \o The \c TabletCanvas class inherits QWidget and
67 receives tablet events. It uses the events to paint on a
68 offscreen pixmap, which it draws onto itself.
69 \o The \c TabletApplication class inherits QApplication. This
70 class handles tablet events that are not sent to \c tabletEvent().
71 We will look at this later.
72 \o The \c main() function creates a \c MainWindow and shows it
73 as a top level window.
77 \section1 MainWindow Class Definition
79 The \c MainWindow creates a \c TabletCanvas and sets it as its
82 \snippet examples/widgets/tablet/mainwindow.h 0
84 The QActions let the user select if the tablets pressure and
85 tilt should change the pen width, color alpha component and color
86 saturation. \c createActions() creates all actions, and \c
87 createMenus() sets up the menus with the actions. We have one
88 QActionGroup for the actions that alter the alpha channel, color
89 saturation and line width respectively. The action groups are
90 connected to the \c alphaActionTriggered(), \c
91 colorSaturationActiontriggered(), and \c
92 lineWidthActionTriggered() slots, which calls functions in \c
96 \section1 MainWindow Class Implementation
98 We start width a look at the constructor \c MainWindow():
100 \snippet examples/widgets/tablet/mainwindow.cpp 0
102 In the constructor we create the canvas, actions, and menus.
103 We set the canvas as the center widget. We also initialize the
104 canvas to match the state of our menus and start drawing with a
107 Here is the implementation of \c brushColorAct():
109 \snippet examples/widgets/tablet/mainwindow.cpp 1
111 We let the user pick a color with a QColorDialog. If it is valid,
112 we set a new drawing color with \c setColor().
114 Here is the implementation of \c alphaActionTriggered():
116 \snippet examples/widgets/tablet/mainwindow.cpp 2
118 The \c TabletCanvas class supports two ways by which the alpha
119 channel of the drawing color can be changed: tablet pressure and
120 tilt. We have one action for each and an action if the alpha
121 channel should not be changed.
123 Here is the implementation of \c lineWidthActionTriggered():
125 \snippet examples/widgets/tablet/mainwindow.cpp 3
127 We check which action is selected in \c lineWidthGroup, and set
128 how the canvas should change the drawing line width.
130 Here is the implementation of \c saturationActionTriggered():
132 \snippet examples/widgets/tablet/mainwindow.cpp 4
134 We check which action is selected in \c colorSaturationGroup, and
135 set how the canvas should change the color saturation of the
138 Here is the implementation of \c saveAct():
140 \snippet examples/widgets/tablet/mainwindow.cpp 5
142 We use the QFileDialog to let the user select a file to save the
143 drawing in. It is the \c TabletCanvas that save the drawing, so we
144 call its \c saveImage() function.
146 Here is the implementation of \c loadAct():
148 \snippet examples/widgets/tablet/mainwindow.cpp 6
150 We let the user select the image file to be opened with
151 a QFileDialog; we then ask the canvas to load the image with \c
154 Here is the implementation of \c aboutAct():
156 \snippet examples/widgets/tablet/mainwindow.cpp 7
158 We show a message box with a short description of the example.
160 \c createActions() creates all actions and action groups of
161 the example. We look at the creation of one action group and its
162 actions. See the \l{Application Example}{application example} if
163 you want a high-level introduction to QActions.
165 Here is the implementation of \c createActions:
167 \snippet examples/widgets/tablet/mainwindow.cpp 8
169 \snippet examples/widgets/tablet/mainwindow.cpp 9
171 We want the user to be able to choose if the drawing color's
172 alpha component should be changed by the tablet pressure or tilt.
173 We have one action for each choice and an action if the alpha
174 channel is not to be changed, i.e, the color is opaque. We make
175 the actions checkable; the \c alphaChannelGroup will then ensure
176 that only one of the actions are checked at any time. The \c
177 triggered() signal is emitted when an action is checked.
180 \snippet examples/widgets/tablet/mainwindow.cpp 10
182 Here is the implementation of \c createMenus():
184 \snippet examples/widgets/tablet/mainwindow.cpp 11
186 We create the menus of the example and add the actions to them.
189 \section1 TabletCanvas Class Definition
191 The \c TabletCanvas class provides a surface on which the
192 user can draw with a tablet.
194 \snippet examples/widgets/tablet/tabletcanvas.h 0
196 The canvas can change the alpha channel, color saturation,
197 and line width of the drawing. We have one enum for each of
198 these; their values decide if it is the tablet pressure or tilt
199 that will alter them. We keep a private variable for each, the \c
200 alphaChannelType, \c colorSturationType, and \c penWidthType,
201 which we provide access functions for.
203 We draw on a QPixmap with \c myPen and \c myBrush using \c
204 myColor. The \c saveImage() and \c loadImage() saves and loads
205 the QPixmap to disk. The pixmap is drawn on the widget in \c
206 paintEvent(). The \c pointerType and \c deviceType keeps the type
207 of pointer, which is either a pen or an eraser, and device
208 currently used on the tablet, which is either a stylus or an
211 The interpretation of events from the tablet is done in \c
212 tabletEvent(); \c paintPixmap(), \c updateBrush(), and \c
213 brushPattern() are helper functions used by \c tabletEvent().
216 \section1 TabletCanvas Class Implementation
218 We start with a look at the constructor:
220 \snippet examples/widgets/tablet/tabletcanvas.cpp 0
222 In the constructor we initialize our class variables. We need
223 to draw the background of our pixmap, as the default is gray.
225 Here is the implementation of \c saveImage():
227 \snippet examples/widgets/tablet/tabletcanvas.cpp 1
229 QPixmap implements functionality to save itself to disk, so we
230 simply call \l{QPixmap::}{save()}.
232 Here is the implementation of \c loadImage():
234 \snippet examples/widgets/tablet/tabletcanvas.cpp 2
236 We simply call \l{QPixmap::}{load()}, which loads the image in \a
239 Here is the implementation of \c tabletEvent():
241 \snippet examples/widgets/tablet/tabletcanvas.cpp 3
243 We get three kind of events to this function: TabletPress,
244 TabletRelease, and TabletMove, which is generated when a device
245 is pressed down on, leaves, or moves on the tablet. We set the \c
246 deviceDown to true when a device is pressed down on the tablet;
247 we then know when we should draw when we receive move events. We
248 have implemented the \c updateBrush() and \c paintPixmap() helper
249 functions to update \c myBrush and \c myPen after the state of \c
250 alphaChannelType, \c colorSaturationType, and \c lineWidthType.
252 Here is the implementation of \c paintEvent():
254 \snippet examples/widgets/tablet/tabletcanvas.cpp 4
256 We simply draw the pixmap to the top left of the widget.
258 Here is the implementation of \c paintPixmap():
260 \snippet examples/widgets/tablet/tabletcanvas.cpp 5
262 In this function we draw on the pixmap based on the movement of the
263 device. If the device used on the tablet is a stylus we want to draw a
264 line between the positions of the stylus recorded in \c polyLine. We
265 also assume that this is a reasonable handling of any unknown device,
266 but update the statusbar with a warning so that the user can see that
267 for his tablet he might have to implement special handling.
268 If it is an airbrush we want to draw a circle of points with a
269 point density based on the tangential pressure, which is the position
270 of the finger wheel on the airbrush. We use the Qt::BrushStyle to
271 draw the points as it has styles that draw points with different
272 density; we select the style based on the tangential pressure in
275 \snippet examples/widgets/tablet/tabletcanvas.cpp 6
277 We return a brush style with a point density that increases with
278 the tangential pressure.
280 In \c updateBrush() we set the pen and brush used for drawing
281 to match \c alphaChannelType, \c lineWidthType, \c
282 colorSaturationType, and \c myColor. We will examine the code to
283 set up \c myBrush and \c myPen for each of these variables:
285 \snippet examples/widgets/tablet/tabletcanvas.cpp 7
287 We fetch the current drawingcolor's hue, saturation, value,
288 and alpha values. \c hValue and \c vValue are set to the
289 horizontal and vertical tilt as a number from 0 to 255. The
290 original values are in degrees from -60 to 60, i.e., 0 equals
291 -60, 127 equals 0, and 255 equals 60 degrees. The angle measured
292 is between the device and the perpendicular of the tablet (see
293 QTabletEvent for an illustration).
295 \snippet examples/widgets/tablet/tabletcanvas.cpp 8
297 The alpha channel of QColor is given as a number between 0
298 and 255 where 0 is transparent and 255 is opaque.
299 \l{QTabletEvent::}{pressure()} returns the pressure as a qreal
300 between 0.0 and 1.0. By subtracting 127 from the tilt values and
301 taking the absolute value we get the smallest alpha values (i.e.,
302 the color is most transparent) when the pen is perpendicular to
303 the tablet. We select the largest of the vertical and horizontal
306 \snippet examples/widgets/tablet/tabletcanvas.cpp 9
308 The colorsaturation is given as a number between 0 and 255. It is
309 set with \l{QColor::}{setHsv()}. We can set the tilt values
310 directly, but must multiply the pressure to a number between 0 and
313 \snippet examples/widgets/tablet/tabletcanvas.cpp 10
315 The width of the pen increases with the pressure. When the pen
316 width is controlled with the tilt we let the width increse with
317 the angle between the device and the perpendicular of the tablet.
319 \snippet examples/widgets/tablet/tabletcanvas.cpp 11
321 We finally check wether the pointer is the stylus or the eraser.
322 If it is the eraser, we set the color to the background color of
323 the pixmap an let the pressure decide the pen width, else we set
324 the colors we have set up previously in the function.
327 \section1 TabletApplication Class Definition
329 We inherit QApplication in this class because we want to
330 reimplement the \l{QApplication::}{event()} function.
332 \snippet examples/widgets/tablet/tabletapplication.h 0
334 We keep a \c TabletCanvas we send the device type of the events we
335 handle in the \c event() function to. The TabletEnterProximity
336 and TabletLeaveProximity events are not sendt to the QApplication
337 object, while other tablet events are sendt to the QWidget's
338 \c event(), which sends them on to \l{QWidget::}{tabletEvent()}.
339 Since we want to handle these events we have implemented \c
343 \section1 TabletApplication Class Implementation
345 Here is the implementation of \c event():
347 \snippet examples/widgets/tablet/tabletapplication.cpp 0
349 We use this function to handle the TabletEnterProximity and
350 TabletLeaveProximity events, which is generated when a device
351 enters and leaves the proximity of the tablet. The intended use of these
352 events is to do work that is dependent on what kind of device is
353 used on the tablet. This way, you don't have to do this work
354 when other events are generated, which is more frequently than the
355 leave and enter proximity events. We call \c setTabletDevice() in
358 \section1 The \c main() function
360 Here is the examples \c main() function:
362 \snippet examples/widgets/tablet/main.cpp 0
364 In the \c main() function we create a \c MainWinow and display it
365 as a top level window. We use the \c TabletApplication class. We
366 need to set the canvas after the application is created. We cannot
367 use classes that implement event handling before an QApplication
368 object is instantiated.