Plug & Paint Example

Screenshot of the Plug & Paint example

A plugin is a dynamic library that can be loaded at run-time to extend an application. Qt makes it possible to create custom plugins and to load them using QPluginLoader. To ensure that plugins don't get lost, it is also possible to link them statically to the executable. The Plug & Paint example uses plugins to support custom brushes, shapes, and image filters. A single plugin can provide multiple brushes, shapes, and/or filters.

If you want to learn how to make your own application extensible through plugins, we recommend that you start by reading this overview, which explains how to make an application use plugins. Afterwards, you can read the Basic Tools and Extra Filters overviews, which show how to implement static and dynamic plugins, respectively.

Plug & Paint consists of the following classes:

  • MainWindow is a QMainWindow subclass that provides the menu system and that contains a PaintArea as the central widget.

  • PaintArea is a QWidget that allows the user to draw using a brush and to insert shapes.

  • PluginDialog is a dialog that shows information about the plugins detected by the application.

  • BrushInterface, ShapeInterface, and FilterInterface are abstract base classes that can be implemented by plugins to provide custom brushes, shapes, and image filters.

The Plugin Interfaces

We will start by reviewing the interfaces defined in interfaces.h. These interfaces are used by the Plug & Paint application to access extra functionality. They are implemented in the plugins.

 
Sélectionnez
class BrushInterface
{
public:
    virtual ~BrushInterface() {}

    virtual QStringList brushes() const = 0;
    virtual QRect mousePress(const QString &brush, QPainter &painter,
                             const QPoint &pos) = 0;
    virtual QRect mouseMove(const QString &brush, QPainter &painter,
                            const QPoint &oldPos, const QPoint &newPos) = 0;
    virtual QRect mouseRelease(const QString &brush, QPainter &painter,
                               const QPoint &pos) = 0;
};

The BrushInterface class declares four pure virtual functions. The first pure virtual function, brushes(), returns a list of strings that identify the brushes provided by the plugin. By returning a QStringList instead of a QString, we make it possible for a single plugin to provide multiple brushes. The other functions have a brush parameter to identify which brush (among those returned by brushes()) is used.

mousePress(), mouseMove(), and mouseRelease() take a QPainter and one or two QPoints, and return a QRect identifying which portion of the image was altered by the brush.

The class also has a virtual destructor. Interface classes usually don't need such a destructor (because it would make little sense to delete the object that implements the interface through a pointer to the interface), but some compilers emit a warning for classes that declare virtual functions but no virtual destructor. We provide the destructor to keep these compilers happy.

 
Sélectionnez
class ShapeInterface
{
public:
    virtual ~ShapeInterface() {}

    virtual QStringList shapes() const = 0;
    virtual QPainterPath generateShape(const QString &shape,
                                       QWidget *parent) = 0;
};

The ShapeInterface class declares a shapes() function that works the same as BrushInterface's brushes() function, and a generateShape() function that has a shape parameter. Shapes are represented by a QPainterPath, a data type that can represent arbitrary 2D shapes or combinations of shapes. The parent parameter can be used by the plugin to pop up a dialog asking the user to specify more information.