source: trunk/doc/src/examples/tablet.qdoc@ 651

Last change on this file since 651 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

File size: 15.5 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the documentation of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42/*!
43 \example widgets/tablet
44 \title Tablet Example
45
46 This example shows how to use a Wacom tablet in Qt applications.
47
48 \image tabletexample.png
49
50 When you use a tablet with Qt applications, \l{QTabletEvent}s are
51 generated. You need to reimplement the
52 \l{QWidget::}{tabletEvent()} event handler if you want to handle
53 tablet events. Events are generated when the device used for
54 drawing enters and leaves the proximity of the tablet (i.e., when
55 it is close but not pressed down on it), when a device is pushed
56 down and released from it, and when a device is moved on the
57 tablet.
58
59 The information available in QTabletEvent depends on the device
60 used. The tablet in this example has two different devices for
61 drawing: a stylus and an airbrush. For both devices the event
62 contains the position of the device, pressure on the tablet,
63 vertical tilt, and horizontal tilt (i.e, the angle between the
64 device and the perpendicular of the tablet). The airbrush has a
65 finger wheel; the position of this is also available in the tablet
66 event.
67
68 In this example we implement a drawing program. You can use the
69 stylus to draw on the tablet as you use a pencil on paper. When
70 you draw with the airbrush you get a spray of paint; the finger
71 wheel is used to change the density of the spray. The pressure and
72 tilt can change the alpha and saturation values of the QColor and the
73 width of the QPen used for drawing.
74
75 The example consists of the following:
76
77 \list
78 \o The \c MainWindow class inherits QMainWindow and creates
79 the examples menus and connect their slots and signals.
80 \o The \c TabletCanvas class inherits QWidget and
81 receives tablet events. It uses the events to paint on a
82 offscreen pixmap, which it draws onto itself.
83 \o The \c TabletApplication class inherits QApplication. This
84 class handles tablet events that are not sent to \c tabletEvent().
85 We will look at this later.
86 \o The \c main() function creates a \c MainWindow and shows it
87 as a top level window.
88 \endlist
89
90
91 \section1 MainWindow Class Definition
92
93 The \c MainWindow creates a \c TabletCanvas and sets it as its
94 center widget.
95
96 \snippet examples/widgets/tablet/mainwindow.h 0
97
98 The QActions let the user select if the tablets pressure and
99 tilt should change the pen width, color alpha component and color
100 saturation. \c createActions() creates all actions, and \c
101 createMenus() sets up the menus with the actions. We have one
102 QActionGroup for the actions that alter the alpha channel, color
103 saturation and line width respectively. The action groups are
104 connected to the \c alphaActionTriggered(), \c
105 colorSaturationActiontriggered(), and \c
106 lineWidthActionTriggered() slots, which calls functions in \c
107 myCanvas.
108
109
110 \section1 MainWindow Class Implementation
111
112 We start width a look at the constructor \c MainWindow():
113
114 \snippet examples/widgets/tablet/mainwindow.cpp 0
115
116 In the constructor we create the canvas, actions, and menus.
117 We set the canvas as the center widget. We also initialize the
118 canvas to match the state of our menus and start drawing with a
119 red color.
120
121 Here is the implementation of \c brushColorAct():
122
123 \snippet examples/widgets/tablet/mainwindow.cpp 1
124
125 We let the user pick a color with a QColorDialog. If it is valid,
126 we set a new drawing color with \c setColor().
127
128 Here is the implementation of \c alphaActionTriggered():
129
130 \snippet examples/widgets/tablet/mainwindow.cpp 2
131
132 The \c TabletCanvas class supports two ways by which the alpha
133 channel of the drawing color can be changed: tablet pressure and
134 tilt. We have one action for each and an action if the alpha
135 channel should not be changed.
136
137 Here is the implementation of \c lineWidthActionTriggered():
138
139 \snippet examples/widgets/tablet/mainwindow.cpp 3
140
141 We check which action is selected in \c lineWidthGroup, and set
142 how the canvas should change the drawing line width.
143
144 Here is the implementation of \c saturationActionTriggered():
145
146 \snippet examples/widgets/tablet/mainwindow.cpp 4
147
148 We check which action is selected in \c colorSaturationGroup, and
149 set how the canvas should change the color saturation of the
150 drawing color.
151
152 Here is the implementation of \c saveAct():
153
154 \snippet examples/widgets/tablet/mainwindow.cpp 5
155
156 We use the QFileDialog to let the user select a file to save the
157 drawing in. It is the \c TabletCanvas that save the drawing, so we
158 call its \c saveImage() function.
159
160 Here is the implementation of \c loadAct():
161
162 \snippet examples/widgets/tablet/mainwindow.cpp 6
163
164 We let the user select the image file to be opened with
165 a QFileDialog; we then ask the canvas to load the image with \c
166 loadImage().
167
168 Here is the implementation of \c aboutAct():
169
170 \snippet examples/widgets/tablet/mainwindow.cpp 7
171
172 We show a message box with a short description of the example.
173
174 \c createActions() creates all actions and action groups of
175 the example. We look at the creation of one action group and its
176 actions. See the \l{Application Example}{application example} if
177 you want a high-level introduction to QActions.
178
179 Here is the implementation of \c createActions:
180
181 \snippet examples/widgets/tablet/mainwindow.cpp 8
182 \dots
183 \snippet examples/widgets/tablet/mainwindow.cpp 9
184
185 We want the user to be able to choose if the drawing color's
186 alpha component should be changed by the tablet pressure or tilt.
187 We have one action for each choice and an action if the alpha
188 channel is not to be changed, i.e, the color is opaque. We make
189 the actions checkable; the \c alphaChannelGroup will then ensure
190 that only one of the actions are checked at any time. The \c
191 triggered() signal is emitted when an action is checked.
192
193 \dots
194 \snippet examples/widgets/tablet/mainwindow.cpp 10
195
196 Here is the implementation of \c createMenus():
197
198 \snippet examples/widgets/tablet/mainwindow.cpp 11
199
200 We create the menus of the example and add the actions to them.
201
202
203 \section1 TabletCanvas Class Definition
204
205 The \c TabletCanvas class provides a surface on which the
206 user can draw with a tablet.
207
208 \snippet examples/widgets/tablet/tabletcanvas.h 0
209
210 The canvas can change the alpha channel, color saturation,
211 and line width of the drawing. We have one enum for each of
212 these; their values decide if it is the tablet pressure or tilt
213 that will alter them. We keep a private variable for each, the \c
214 alphaChannelType, \c colorSturationType, and \c penWidthType,
215 which we provide access functions for.
216
217 We draw on a QPixmap with \c myPen and \c myBrush using \c
218 myColor. The \c saveImage() and \c loadImage() saves and loads
219 the QPixmap to disk. The pixmap is drawn on the widget in \c
220 paintEvent(). The \c pointerType and \c deviceType keeps the type
221 of pointer, which is either a pen or an eraser, and device
222 currently used on the tablet, which is either a stylus or an
223 airbrush.
224
225 The interpretation of events from the tablet is done in \c
226 tabletEvent(); \c paintPixmap(), \c updateBrush(), and \c
227 brushPattern() are helper functions used by \c tabletEvent().
228
229
230 \section1 TabletCanvas Class Implementation
231
232 We start with a look at the constructor:
233
234 \snippet examples/widgets/tablet/tabletcanvas.cpp 0
235
236 In the constructor we initialize our class variables. We need
237 to draw the background of our pixmap, as the default is gray.
238
239 Here is the implementation of \c saveImage():
240
241 \snippet examples/widgets/tablet/tabletcanvas.cpp 1
242
243 QPixmap implements functionality to save itself to disk, so we
244 simply call \l{QPixmap::}{save()}.
245
246 Here is the implementation of \c loadImage():
247
248 \snippet examples/widgets/tablet/tabletcanvas.cpp 2
249
250 We simply call \l{QPixmap::}{load()}, which loads the image in \a
251 file.
252
253 Here is the implementation of \c tabletEvent():
254
255 \snippet examples/widgets/tablet/tabletcanvas.cpp 3
256
257 We get three kind of events to this function: TabletPress,
258 TabletRelease, and TabletMove, which is generated when a device
259 is pressed down on, leaves, or moves on the tablet. We set the \c
260 deviceDown to true when a device is pressed down on the tablet;
261 we then know when we should draw when we receive move events. We
262 have implemented the \c updateBrush() and \c paintPixmap() helper
263 functions to update \c myBrush and \c myPen after the state of \c
264 alphaChannelType, \c colorSaturationType, and \c lineWidthType.
265
266 Here is the implementation of \c paintEvent():
267
268 \snippet examples/widgets/tablet/tabletcanvas.cpp 4
269
270 We simply draw the pixmap to the top left of the widget.
271
272 Here is the implementation of \c paintPixmap():
273
274 \snippet examples/widgets/tablet/tabletcanvas.cpp 5
275
276 In this function we draw on the pixmap based on the movement of the
277 device. If the device used on the tablet is a stylus we want to draw a
278 line between the positions of the stylus recorded in \c polyLine. We
279 also assume that this is a reasonable handling of any unknown device,
280 but update the statusbar with a warning so that the user can see that
281 for his tablet he might have to implement special handling.
282 If it is an airbrush we want to draw a circle of points with a
283 point density based on the tangential pressure, which is the position
284 of the finger wheel on the airbrush. We use the Qt::BrushStyle to
285 draw the points as it has styles that draw points with different
286 density; we select the style based on the tangential pressure in
287 \c brushPattern().
288
289 \snippet examples/widgets/tablet/tabletcanvas.cpp 6
290
291 We return a brush style with a point density that increases with
292 the tangential pressure.
293
294 In \c updateBrush() we set the pen and brush used for drawing
295 to match \c alphaChannelType, \c lineWidthType, \c
296 colorSaturationType, and \c myColor. We will examine the code to
297 set up \c myBrush and \c myPen for each of these variables:
298
299 \snippet examples/widgets/tablet/tabletcanvas.cpp 7
300
301 We fetch the current drawingcolor's hue, saturation, value,
302 and alpha values. \c hValue and \c vValue are set to the
303 horizontal and vertical tilt as a number from 0 to 255. The
304 original values are in degrees from -60 to 60, i.e., 0 equals
305 -60, 127 equals 0, and 255 equals 60 degrees. The angle measured
306 is between the device and the perpendicular of the tablet (see
307 QTabletEvent for an illustration).
308
309 \snippet examples/widgets/tablet/tabletcanvas.cpp 8
310
311 The alpha channel of QColor is given as a number between 0
312 and 255 where 0 is transparent and 255 is opaque.
313 \l{QTabletEvent::}{pressure()} returns the pressure as a qreal
314 between 0.0 and 1.0. By subtracting 127 from the tilt values and
315 taking the absolute value we get the smallest alpha values (i.e.,
316 the color is most transparent) when the pen is perpendicular to
317 the tablet. We select the largest of the vertical and horizontal
318 tilt value.
319
320 \snippet examples/widgets/tablet/tabletcanvas.cpp 9
321
322 The colorsaturation is given as a number between 0 and 255. It is
323 set with \l{QColor::}{setHsv()}. We can set the tilt values
324 directly, but must multiply the pressure to a number between 0 and
325 255.
326
327 \snippet examples/widgets/tablet/tabletcanvas.cpp 10
328
329 The width of the pen increases with the pressure. When the pen
330 width is controlled with the tilt we let the width increse with
331 the angle between the device and the perpendicular of the tablet.
332
333 \snippet examples/widgets/tablet/tabletcanvas.cpp 11
334
335 We finally check wether the pointer is the stylus or the eraser.
336 If it is the eraser, we set the color to the background color of
337 the pixmap an let the pressure decide the pen width, else we set
338 the colors we have set up previously in the function.
339
340
341 \section1 TabletApplication Class Definition
342
343 We inherit QApplication in this class because we want to
344 reimplement the \l{QApplication::}{event()} function.
345
346 \snippet examples/widgets/tablet/tabletapplication.h 0
347
348 We keep a \c TabletCanvas we send the device type of the events we
349 handle in the \c event() function to. The TabletEnterProximity
350 and TabletLeaveProximity events are not sendt to the QApplication
351 object, while other tablet events are sendt to the QWidget's
352 \c event(), which sends them on to \l{QWidget::}{tabletEvent()}.
353 Since we want to handle these events we have implemented \c
354 TabletApplication.
355
356
357 \section1 TabletApplication Class Implementation
358
359 Here is the implementation of \c event():
360
361 \snippet examples/widgets/tablet/tabletapplication.cpp 0
362
363 We use this function to handle the TabletEnterProximity and
364 TabletLeaveProximity events, which is generated when a device
365 enters and leaves the proximity of the tablet. The intended use of these
366 events is to do work that is dependent on what kind of device is
367 used on the tablet. This way, you don't have to do this work
368 when other events are generated, which is more frequently than the
369 leave and enter proximity events. We call \c setTabletDevice() in
370 \c TabletCanvas.
371
372 \section1 The \c main() function
373
374 Here is the examples \c main() function:
375
376 \snippet examples/widgets/tablet/main.cpp 0
377
378 In the \c main() function we create a \c MainWinow and display it
379 as a top level window. We use the \c TabletApplication class. We
380 need to set the canvas after the application is created. We cannot
381 use classes that implement event handling before an QApplication
382 object is instantiated.
383*/
Note: See TracBrowser for help on using the repository browser.