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

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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