source: trunk/doc/src/examples/plugandpaint.qdoc@ 109

Last change on this file since 109 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 23.8 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the documentation of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** 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 are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42/*!
43 \example tools/plugandpaint
44 \title Plug & Paint Example
45
46 The Plug & Paint example demonstrates how to write Qt
47 applications that can be extended through plugins.
48
49 \image plugandpaint.png Screenshot of the Plug & Paint example
50
51 A plugin is a dynamic library that can be loaded at run-time to
52 extend an application. Qt makes it possible to create custom
53 plugins and to load them using QPluginLoader. To ensure that
54 plugins don't get lost, it is also possible to link them
55 statically to the executable. The Plug & Paint example uses
56 plugins to support custom brushes, shapes, and image filters. A
57 single plugin can provide multiple brushes, shapes, and/or
58 filters.
59
60 If you want to learn how to make your own application extensible
61 through plugins, we recommend that you start by reading this
62 overview, which explains how to make an application use plugins.
63 Afterward, you can read the
64 \l{tools/plugandpaintplugins/basictools}{Basic Tools} and
65 \l{tools/plugandpaintplugins/extrafilters}{Extra Filters}
66 overviews, which show how to implement static and dynamic
67 plugins, respectively.
68
69 Plug & Paint consists of the following classes:
70
71 \list
72 \o \c MainWindow is a QMainWindow subclass that provides the menu
73 system and that contains a \c PaintArea as the central widget.
74 \o \c PaintArea is a QWidget that allows the user to draw using a
75 brush and to insert shapes.
76 \o \c PluginDialog is a dialog that shows information about the
77 plugins detected by the application.
78 \o \c BrushInterface, \c ShapeInterface, and \c FilterInterface are
79 abstract base classes that can be implemented by plugins to
80 provide custom brushes, shapes, and image filters.
81 \endlist
82
83 \section1 The Plugin Interfaces
84
85 We will start by reviewing the interfaces defined in \c
86 interfaces.h. These interfaces are used by the Plug & Paint
87 application to access extra functionality. They are implemented
88 in the plugins.
89
90
91 \snippet examples/tools/plugandpaint/interfaces.h 0
92
93 The \c BrushInterface class declares four pure virtual functions.
94 The first pure virtual function, \c brushes(), returns a list of
95 strings that identify the brushes provided by the plugin. By
96 returning a QStringList instead of a QString, we make it possible
97 for a single plugin to provide multiple brushes. The other
98 functions have a \c brush parameter to identify which brush
99 (among those returned by \c brushes()) is used.
100
101 \c mousePress(), \c mouseMove(), and \c mouseRelease() take a
102 QPainter and one or two \l{QPoint}s, and return a QRect
103 identifying which portion of the image was altered by the brush.
104
105 The class also has a virtual destructor. Interface classes
106 usually don't need such a destructor (because it would make
107 little sense to \c delete the object that implements the
108 interface through a pointer to the interface), but some compilers
109 emit a warning for classes that declare virtual functions but no
110 virtual destructor. We provide the destructor to keep these
111 compilers happy.
112
113 \snippet examples/tools/plugandpaint/interfaces.h 1
114
115 The \c ShapeInterface class declares a \c shapes() function that
116 works the same as \c{BrushInterface}'s \c brushes() function, and
117 a \c generateShape() function that has a \c shape parameter.
118 Shapes are represented by a QPainterPath, a data type that can
119 represent arbitrary 2D shapes or combinations of shapes. The \c
120 parent parameter can be used by the plugin to pop up a dialog
121 asking the user to specify more information.
122
123 \snippet examples/tools/plugandpaint/interfaces.h 2
124
125 The \c FilterInterface class declares a \c filters() function
126 that returns a list of filter names, and a \c filterImage()
127 function that applies a filter to an image.
128
129 \snippet examples/tools/plugandpaint/interfaces.h 4
130
131 To make it possible to query at run-time whether a plugin
132 implements a given interface, we must use the \c
133 Q_DECLARE_INTERFACE() macro. The first argument is the name of
134 the interface. The second argument is a string identifying the
135 interface in a unique way. By convention, we use a "Java package
136 name" syntax to identify interfaces. If we later change the
137 interfaces, we must use a different string to identify the new
138 interface; otherwise, the application might crash. It is therefore
139 a good idea to include a version number in the string, as we did
140 above.
141
142 The \l{tools/plugandpaintplugins/basictools}{Basic Tools} plugin
143 and the \l{tools/plugandpaintplugins/extrafilters}{Extra Filters}
144 plugin shows how to derive from \c BrushInterface, \c
145 ShapeInterface, and \c FilterInterface.
146
147 A note on naming: It might have been tempting to give the \c
148 brushes(), \c shapes(), and \c filters() functions a more generic
149 name, such as \c keys() or \c features(). However, that would
150 have made multiple inheritance impractical. When creating
151 interfaces, we should always try to give unique names to the pure
152 virtual functions.
153
154 \section1 The MainWindow Class
155
156 The \c MainWindow class is a standard QMainWindow subclass, as
157 found in many of the other examples (e.g.,
158 \l{mainwindows/application}{Application}). Here, we'll
159 concentrate on the parts of the code that are related to plugins.
160
161 \snippet examples/tools/plugandpaint/mainwindow.cpp 4
162
163 The \c loadPlugins() function is called from the \c MainWindow
164 constructor to detect plugins and update the \gui{Brush},
165 \gui{Shapes}, and \gui{Filters} menus. We start by handling static
166 plugins (available through QPluginLoader::staticInstances())
167
168 To the application that uses the plugin, a Qt plugin is simply a
169 QObject. That QObject implements plugin interfaces using multiple
170 inheritance.
171
172 \snippet examples/tools/plugandpaint/mainwindow.cpp 5
173
174 The next step is to load dynamic plugins. We initialize the \c
175 pluginsDir member variable to refer to the \c plugins
176 subdirectory of the Plug & Paint example. On Unix, this is just a
177 matter of initializing the QDir variable with
178 QApplication::applicationDirPath(), the path of the executable
179 file, and to do a \l{QDir::cd()}{cd()}. On Windows and Mac OS X,
180 this file is usually located in a subdirectory, so we need to
181 take this into account.
182
183 \snippet examples/tools/plugandpaint/mainwindow.cpp 6
184 \snippet examples/tools/plugandpaint/mainwindow.cpp 7
185 \snippet examples/tools/plugandpaint/mainwindow.cpp 8
186
187 We use QDir::entryList() to get a list of all files in that
188 directory. Then we iterate over the result using \l foreach and
189 try to load the plugin using QPluginLoader.
190
191 The QObject provided by the plugin is accessible through
192 QPluginLoader::instance(). If the dynamic library isn't a Qt
193 plugin, or if it was compiled against an incompatible version of
194 the Qt library, QPluginLoader::instance() returns a null pointer.
195
196 If QPluginLoader::instance() is non-null, we add it to the menus.
197
198 \snippet examples/tools/plugandpaint/mainwindow.cpp 9
199
200 At the end, we enable or disable the \gui{Brush}, \gui{Shapes},
201 and \gui{Filters} menus based on whether they contain any items.
202
203 \snippet examples/tools/plugandpaint/mainwindow.cpp 10
204
205 For each plugin (static or dynamic), we check which interfaces it
206 implements using \l qobject_cast(). First, we try to cast the
207 plugin instance to a \c BrushInterface; if it works, we call the
208 private function \c addToMenu() with the list of brushes returned
209 by \c brushes(). Then we do the same with the \c ShapeInterface
210 and the \c FilterInterface.
211
212 \snippet examples/tools/plugandpaint/mainwindow.cpp 3
213
214 The \c aboutPlugins() slot is called on startup and can be
215 invoked at any time through the \gui{About Plugins} action. It
216 pops up a \c PluginDialog, providing information about the loaded
217 plugins.
218
219 \image plugandpaint-plugindialog.png Screenshot of the Plugin dialog
220
221
222 The \c addToMenu() function is called from \c loadPlugin() to
223 create \l{QAction}s for custom brushes, shapes, or filters and
224 add them to the relevant menu. The QAction is created with the
225 plugin from which it comes from as the parent; this makes it
226 convenient to get access to the plugin later.
227
228 \snippet examples/tools/plugandpaint/mainwindow.cpp 0
229
230 The \c changeBrush() slot is invoked when the user chooses one of
231 the brushes from the \gui{Brush} menu. We start by finding out
232 which action invoked the slot using QObject::sender(). Then we
233 get the \c BrushInterface out of the plugin (which we
234 conveniently passed as the QAction's parent) and we call \c
235 PaintArea::setBrush() with the \c BrushInterface and the string
236 identifying the brush. Next time the user draws on the paint
237 area, \c PaintArea will use this brush.
238
239 \snippet examples/tools/plugandpaint/mainwindow.cpp 1
240
241 The \c insertShape() is invoked when the use chooses one of the
242 shapes from the \gui{Shapes} menu. We retrieve the QAction that
243 invoked the slot, then the \c ShapeInterface associated with that
244 QAction, and finally we call \c ShapeInterface::generateShape()
245 to obtain a QPainterPath.
246
247 \snippet examples/tools/plugandpaint/mainwindow.cpp 2
248
249 The \c applyFilter() slot is similar: We retrieve the QAction
250 that invoked the slot, then the \c FilterInterface associated to
251 that QAction, and finally we call \c
252 FilterInterface::filterImage() to apply the filter onto the
253 current image.
254
255 \section1 The PaintArea Class
256
257 The \c PaintArea class contains some code that deals with \c
258 BrushInterface, so we'll review it briefly.
259
260 \snippet examples/tools/plugandpaint/paintarea.cpp 0
261
262 In \c setBrush(), we simply store the \c BrushInterface and the
263 brush that are given to us by \c MainWindow.
264
265 \snippet examples/tools/plugandpaint/paintarea.cpp 1
266
267 In the \l{QWidget::mouseMoveEvent()}{mouse move event handler},
268 we call the \c BrushInterface::mouseMove() function on the
269 current \c BrushInterface, with the current brush. The mouse
270 press and mouse release handlers are very similar.
271
272 \section1 The PluginDialog Class
273
274 The \c PluginDialog class provides information about the loaded
275 plugins to the user. Its constructor takes a path to the plugins
276 and a list of plugin file names. It calls \c findPlugins()
277 to fill the QTreeWdiget with information about the plugins:
278
279 \snippet examples/tools/plugandpaint/plugindialog.cpp 0
280
281 The \c findPlugins() is very similar to \c
282 MainWindow::loadPlugins(). It uses QPluginLoader to access the
283 static and dynamic plugins. Its helper function \c
284 populateTreeWidget() uses \l qobject_cast() to find out which
285 interfaces are implemented by the plugins:
286
287 \snippet examples/tools/plugandpaint/plugindialog.cpp 1
288
289 \section1 Importing Static Plugins
290
291 The \l{tools/plugandpaintplugins/basictools}{Basic Tools} plugin
292 is built as a static plugin, to ensure that it is always
293 available to the application. This requires using the
294 Q_IMPORT_PLUGIN() macro somewhere in the application (in a \c
295 .cpp file) and specifying the plugin in the \c .pro file.
296
297 For Plug & Paint, we have chosen to put Q_IMPORT_PLUGIN() in \c
298 main.cpp:
299
300 \snippet examples/tools/plugandpaint/main.cpp 0
301
302 The argument to Q_IMPORT_PLUGIN() is the plugin's name, as
303 specified with Q_EXPORT_PLUGIN2() in the \l{Exporting the
304 Plugin}{plugin}.
305
306 In the \c .pro file, we need to specify the static library.
307 Here's the project file for building Plug & Paint:
308
309 \snippet examples/tools/plugandpaint/plugandpaint.pro 0
310
311 The \c LIBS line variable specifies the library \c pnp_basictools
312 located in the \c ../plugandpaintplugins/basictools directory.
313 (Although the \c LIBS syntax has a distinct Unix flavor, \c qmake
314 supports it on all platforms.)
315
316 The \c CONFIG() code at the end is necessary for this example
317 because the example is part of the Qt distribution and Qt can be
318 configured to be built simultaneously in debug and in release
319 modes. You don't need to for your own plugin applications.
320
321 This completes our review of the Plug & Paint application. At
322 this point, you might want to take a look at the
323 \l{tools/plugandpaintplugins/basictools}{Basic Tools} example
324 plugin.
325*/
326
327/*!
328 \example tools/plugandpaintplugins/basictools
329 \title Plug & Paint Basic Tools Example
330
331 The Basic Tools example is a static plugin for the
332 \l{tools/plugandpaint}{Plug & Paint} example. It provides a set
333 of basic brushes, shapes, and filters. Through the Basic Tools
334 example, we will review the four steps involved in writing a Qt
335 plugin:
336
337 \list 1
338 \o Declare a plugin class.
339 \o Implement the interfaces provided by the plugin.
340 \o Export the plugin using the Q_EXPORT_PLUGIN2() macro.
341 \o Build the plugin using an adequate \c .pro file.
342 \endlist
343
344 \section1 Declaration of the Plugin Class
345
346 \snippet examples/tools/plugandpaintplugins/basictools/basictoolsplugin.h 0
347
348 We start by including \c interfaces.h, which defines the plugin
349 interfaces for the \l{tools/plugandpaint}{Plug & Paint}
350 application. For the \c #include to work, we need to add an \c
351 INCLUDEPATH entry to the \c .pro file with the path to Qt's \c
352 examples/tools directory.
353
354 The \c BasicToolsPlugin class is a QObject subclass that
355 implements the \c BrushInterface, the \c ShapeInterface, and the
356 \c FilterInterface. This is done through multiple inheritance.
357 The \c Q_INTERFACES() macro is necessary to tell \l{moc}, Qt's
358 meta-object compiler, that the base classes are plugin
359 interfaces. Without the \c Q_INTERFACES() macro, we couldn't use
360 \l qobject_cast() in the \l{tools/plugandpaint}{Plug & Paint}
361 application to detect interfaces.
362
363 \snippet examples/tools/plugandpaintplugins/basictools/basictoolsplugin.h 2
364
365 In the \c public section of the class, we declare all the
366 functions from the three interfaces.
367
368 \section1 Implementation of the Brush Interface
369
370 Let's now review the implementation of the \c BasicToolsPlugin
371 member functions inherited from \c BrushInterface.
372
373 \snippet examples/tools/plugandpaintplugins/basictools/basictoolsplugin.cpp 0
374
375 The \c brushes() function returns a list of brushes provided by
376 this plugin. We provide three brushes: \gui{Pencil}, \gui{Air
377 Brush}, and \gui{Random Letters}.
378
379 \snippet examples/tools/plugandpaintplugins/basictools/basictoolsplugin.cpp 1
380
381 On a mouse press event, we just call \c mouseMove() to draw the
382 spot where the event occurred.
383
384 \snippet examples/tools/plugandpaintplugins/basictools/basictoolsplugin.cpp 2
385
386 In \c mouseMove(), we start by saving the state of the QPainter
387 and we compute a few variables that we'll need later.
388
389 \snippet examples/tools/plugandpaintplugins/basictools/basictoolsplugin.cpp 3
390
391 Then comes the brush-dependent part of the code:
392
393 \list
394 \o If the brush is \gui{Pencil}, we just call
395 QPainter::drawLine() with the current QPen.
396
397 \o If the brush is \gui{Air Brush}, we start by setting the
398 painter's QBrush to Qt::Dense6Pattern to obtain a dotted
399 pattern. Then we draw a circle filled with that QBrush several
400 times, resulting in a thick line.
401
402 \o If the brush is \gui{Random Letters}, we draw a random letter
403 at the new cursor position. Most of the code is for setting
404 the font to be bold and larger than the default font and for
405 computing an appropriate bounding rect.
406 \endlist
407
408 At the end, we restore the painter state to what it was upon
409 entering the function and we return the bounding rectangle.
410
411 \snippet examples/tools/plugandpaintplugins/basictools/basictoolsplugin.cpp 4
412
413 When the user releases the mouse, we do nothing and return an
414 empty QRect.
415
416 \section1 Implementation of the Shape Interface
417
418 \snippet examples/tools/plugandpaintplugins/basictools/basictoolsplugin.cpp 5
419
420 The plugin provides three shapes: \gui{Circle}, \gui{Star}, and
421 \gui{Text...}. The three dots after \gui{Text} are there because
422 the shape pops up a dialog asking for more information. We know
423 that the shape names will end up in a menu, so we include the
424 three dots in the shape name.
425
426 A cleaner but more complicated design would have been to
427 distinguish between the internal shape name and the name used in
428 the user interface.
429
430 \snippet examples/tools/plugandpaintplugins/basictools/basictoolsplugin.cpp 6
431
432 The \c generateShape() creates a QPainterPath for the specified
433 shape. If the shape is \gui{Text}, we pop up a QInputDialog to
434 let the user enter some text.
435
436 \section1 Implementation of the Filter Interface
437
438 \snippet examples/tools/plugandpaintplugins/basictools/basictoolsplugin.cpp 7
439
440 The plugin provides three filters: \gui{Invert Pixels}, \gui{Swap
441 RGB}, and \gui{Grayscale}.
442
443 \snippet examples/tools/plugandpaintplugins/basictools/basictoolsplugin.cpp 8
444
445 The \c filterImage() function takes a filter name and a QImage as
446 parameters and returns an altered QImage. The first thing we do
447 is to convert the image to a 32-bit RGB format, to ensure that
448 the algorithms will work as expected. For example,
449 QImage::invertPixels(), which is used to implement the
450 \gui{Invert Pixels} filter, gives counterintuitive results for
451 8-bit images, because they invert the indices into the color
452 table instead of inverting the color table's entries.
453
454 \section1 Exporting the Plugin
455
456 Whereas applications have a \c main() function as their entry
457 point, plugins need to contain exactly one occurrence of the
458 Q_EXPORT_PLUGIN2() macro to specify which class provides the
459 plugin:
460
461 \snippet examples/tools/plugandpaintplugins/basictools/basictoolsplugin.cpp 9
462
463 This line may appear in any \c .cpp file that is part of the
464 plugin's source code.
465
466 \section1 The .pro File
467
468 Here's the project file for building the Basic Tools plugin:
469
470 \snippet examples/tools/plugandpaintplugins/basictools/basictools.pro 0
471
472 The \c .pro file differs from typical \c .pro files in many
473 respects. First, it starts with a \c TEMPLATE entry specifying \c
474 lib. (The default template is \c app.) It also adds \c plugin to
475 the \c CONFIG variable. This is necessary on some platforms to
476 avoid generating symbolic links with version numbers in the file
477 name, which is appropriate for most dynamic libraries but not for
478 plugins.
479
480 To make the plugin a static plugin, all that is required is to
481 specify \c static in addition to \c plugin. The
482 \l{tools/plugandpaintplugins/extrafilters}{Extra Filters} plugin,
483 which is compiled as a dynamic plugin, doesn't specify \c static
484 in its \c .pro file.
485
486 The \c INCLUDEPATH variable sets the search paths for global
487 headers (i.e., header files included using \c{#include <...>}).
488 We add Qt's \c examples/tools directory (strictly speaking,
489 \c{examples/tools/plugandpaintplugins/basictools/../..}) to the
490 list, so that we can include \c <plugandpaint/interfaces.h>.
491
492 The \c TARGET variable specifies which name we want to give the
493 target library. We use \c pnp_ as the prefix to show that the
494 plugin is designed to work with Plug & Paint. On Unix, \c lib is
495 also prepended to that name. On all platforms, a
496 platform-specific suffix is appended (e.g., \c .dll on Windows,
497 \c .a on Linux).
498
499 The \c CONFIG() code at the end is necessary for this example
500 because the example is part of the Qt distribution and Qt can be
501 configured to be built simultaneously in debug and in release
502 modes. You don't need to for your own plugins.
503*/
504
505/*!
506 \example tools/plugandpaintplugins/extrafilters
507 \title Plug & Paint Extra Filters Example
508
509 The Extra Filters example is a plugin for the
510 \l{tools/plugandpaint}{Plug & Paint} example. It provides a set
511 of filters in addition to those provided by the
512 \l{tools/plugandpaintplugins/basictools}{Basic Tools} plugin.
513
514 Since the approach is identical to
515 \l{tools/plugandpaintplugins/basictools}{Basic Tools}, we won't
516 review the code here. The only part of interes is the
517 \c .pro file, since Extra Filters is a dynamic plugin
518 (\l{tools/plugandpaintplugins/basictools}{Basic Tools} is
519 linked statically into the Plug & Paint executable).
520
521 Here's the project file for building the Extra Filters plugin:
522
523 \snippet examples/tools/plugandpaintplugins/extrafilters/extrafilters.pro 0
524
525 The \c .pro file differs from typical \c .pro files in many
526 respects. First, it starts with a \c TEMPLATE entry specifying \c
527 lib. (The default template is \c app.) It also adds \c plugin to
528 the \c CONFIG variable. This is necessary on some platforms to
529 avoid generating symbolic links with version numbers in the file
530 name, which is appropriate for most dynamic libraries but not for
531 plugins.
532
533 The \c INCLUDEPATH variable sets the search paths for global
534 headers (i.e., header files included using \c{#include <...>}).
535 We add Qt's \c examples/tools directory (strictly speaking,
536 \c{examples/tools/plugandpaintplugins/basictools/../..}) to the
537 list, so that we can include \c <plugandpaint/interfaces.h>.
538
539 The \c TARGET variable specifies which name we want to give the
540 target library. We use \c pnp_ as the prefix to show that the
541 plugin is designed to work with Plug & Paint. On Unix, \c lib is
542 also prepended to that name. On all platforms, a
543 platform-specific suffix is appended (e.g., \c .dll on Windows,
544 \c .so on Linux).
545
546 The \c DESTDIR variable specifies where we want to install the
547 plugin. We put it in Plug & Paint's \c plugins subdirectory,
548 since that's where the application looks for dynamic plugins.
549
550 The \c CONFIG() code at the end is necessary for this example
551 because the example is part of the Qt distribution and Qt can be
552 configured to be built simultaneously in debug and in release
553 modes. You don't need to for your own plugins.
554*/
Note: See TracBrowser for help on using the repository browser.