Home · All Classes · Main Classes · Grouped Classes · Modules · Functions

Container Extension Example

Files:

The Container Extension example shows how to create a custom multi-page plugin for Qt Designer using the QDesignerContainerExtension class.

To provide a custom widget that can be used with Qt Designer, we need to supply a self-contained implementation. In this example we use a custom multi-page widget designed to show the container extension feature.

An extension is an object which modifies the behavior of Qt Designer. The QDesignerContainerExtension enables Qt Designer to manage and manipulate a custom multi-page widget, i.e. adding and deleting pages to the widget.

There are four available types of extensions in Qt Designer:

You can use all the extensions following the same pattern as in this example, only replacing the respective extension base class. For more information, see the QtDesigner Module.

The Container Extension example consists of four classes:

The project file for custom widget plugins needs some additional information to ensure that they will work within Qt Designer. For example, custom widget plugins rely on components supplied with Qt Designer, and this must be specified in the project file that we use. We will first take a look at the plugin's project file.

Then we will continue by reviewing the MultiPageWidgetPlugin class, and take a look at the MultiPageWidgetExtensionFactory and MultiPageWidgetContainerExtension classes. Finally, we will take a quick look at the MultiPageWidget class definition.

The Project File: containerextension.pro

    TEMPLATE = lib
    CONFIG  += designer plugin
    DESTDIR  = $$QT_BUILD_TREE/plugins/designer

The TEMPLATE variable's value makes qmake create the custom widget as a library. Later, we will ensure that the widget will be recognized as a plugin by Qt by using the Q_EXPORT_PLUGIN() macro to export the relevant widget information.

The CONFIG variable contains two values, designer and plugin:

When Qt is configured to build in both debug and release modes, Qt Designer will be built in release mode. When this occurs, it is necessary to ensure that plugins are also built in release mode. For that reason you might have to add a release value to your CONFIG variable. Otherwise, if a plugin is built in a mode that is incompatible with Qt Designer, it won't be loaded and installed. For more information about plugins, see the How to Create Qt Plugins documentation.

The DESTDIR variable's value makes qmake install the plugin alongside the other Qt Designer widget plugins which is useful for testing purposes.

    HEADERS += multipagewidget.h \
               multipagewidgetplugin.h \
               multipagewidgetcontainerextension.h \
               multipagewidgetextensionfactory.h

    SOURCES += multipagewidget.cpp \
               multipagewidgetplugin.cpp \
               multipagewidgetcontainerextension.cpp \
               multipagewidgetextensionfactory.cpp

The header and source files for the widget are declared in the usual way, and in addition we provide an implementation of the plugin interface so that Qt Designer can use the custom widget. In this particular example we also provide implementations of the container extension interface and the extension factory.

MultiPageWidgetPlugin Class Definition

The MultiPageWidgetPlugin class expose the MultiPageWidget class to Qt Designer. Its definition is equivalent to the Custom Widget Plugin example's plugin class which is explained in detail. The only part of the class definition that is specific to this particular custom widget is the class name:

    #ifndef MULTIPAGEWIDGETPLUGIN_H
    #define MULTIPAGEWIDGETPLUGIN_H

    #include <QtDesigner/QDesignerCustomWidgetInterface>

    class QIcon;
    class QWidget;

    class MultiPageWidgetPlugin: public QObject, public QDesignerCustomWidgetInterface
    {
        Q_OBJECT
        Q_INTERFACES(QDesignerCustomWidgetInterface)
    public:
        MultiPageWidgetPlugin(QObject *parent = 0);

        QString name() const;
        QString group() const;
        QString toolTip() const;
        QString whatsThis() const;
        QString includeFile() const;
        QIcon icon() const;
        bool isContainer() const;
        QWidget *createWidget(QWidget *parent);
        bool isInitialized() const;
        void initialize(QDesignerFormEditorInterface *formEditor);
        QString domXml() const;

    private:
        bool initialized;
    };

    #endif

The plugin class provides Qt Designer with basic information about our plugin, such as its class name and its include file. Furthermore it knows how to create instances of the MultiPageWidget widget. MultiPageWidgetPlugin also defines the initialize() function which is called after the plugin is loaded into Qt Designer. The function's QDesignerFormEditorInterface parameter provides the plugin with a gateway to all of Qt Designer's API's.

The MultiPageWidgetPlugin class inherits from both QObject and QDesignerCustomWidgetInterface. It is important to remember, when using multiple inheritance, to ensure that all the interfaces (i.e. the classes that doesn't inherit Q_OBJECT) are made known to the meta object system using the Q_INTERFACES() macro. This enables Qt Designer to use qobject_cast() to query for supported interfaces using nothing but a QObject pointer.

MultiPageWidgetPlugin Class Implementation

The MultiPageWidgetPlugin class implementation is in most parts equivalent to the Custom Widget Plugin example's plugin class:

    MultiPageWidgetPlugin::MultiPageWidgetPlugin(QObject *parent)
        :QObject(parent)
    {
        initialized = false;
    }

    QString MultiPageWidgetPlugin::name() const
    {
        return QString("MultiPageWidget");
    }

    QString MultiPageWidgetPlugin::group() const
    {
        return QString("Display Widgets [Examples]");
    }

    QString MultiPageWidgetPlugin::toolTip() const
    {
        return "";
    }

    QString MultiPageWidgetPlugin::whatsThis() const
    {
        return "";
    }

    QString MultiPageWidgetPlugin::includeFile() const
    {
        return QString("multipagewidget.h");
    }

    QIcon MultiPageWidgetPlugin::icon() const
    {
        return QIcon();
    }

    QWidget *MultiPageWidgetPlugin::createWidget(QWidget *parent)
    {
        MultiPageWidget *widget = new MultiPageWidget(parent);
        return widget;
    }

    bool MultiPageWidgetPlugin::isInitialized() const
    {
        return initialized;
    }

    bool MultiPageWidgetPlugin::isContainer() const
    {
        return true;
    }

One of the functions that differ is the isContainer() function which returns true in this example since our custom widget is intended to be used as a container. Note also the initialize() function:

    void MultiPageWidgetPlugin::initialize(QDesignerFormEditorInterface *formEditor)
    {
        if (initialized)
            return;

The initialize() function takes a QDesignerFormEditorInterface object as argument. The QDesignerFormEditorInterface class provides access to Qt Designer's components.

In Qt Designer you can create two kinds of plugins: custom widget plugins and tool plugins. QDesignerFormEditorInterface provides access to all the Qt Designer components that you normally need to create a tool plugin: the extension manager, the object inspector, the property editor and the widget box. Custom widget plugins have access to the same components.

        QExtensionManager *manager = formEditor->extensionManager();

When creating extensions associated with custom widget plugins, we need to access Qt Designer's current extension manager which we retrieve from the QDesignerFormEditorInterface parameter.

Qt Designer's QDesignerFormEditorInterface holds information about all Qt Designer's components: The action editor, the object inspector, the property editor, the widget box, and the extension and form window managers.

The QExtensionManager class provides extension management facilities for Qt Designer. Using Qt Designer's current extension manager you can retrieve the extension for a given object. You can also register and unregister an extension for a given object. Remember that an extension is an object which modifies the behavior of Qt Designer.

When registrering an extension, it is actually the associated extension factory that is registered. In Qt Designer, extension factories are used to look up and create named extensions as they are required. So, in this example, the container extension itself is not created until Qt Designer must know whether the associated widget is a container, or not.

        QExtensionFactory *factory = new MultiPageWidgetExtensionFactory(manager);

        Q_ASSERT(manager != 0);
        manager->registerExtensions(factory, Q_TYPEID(QDesignerContainerExtension));

        initialized = true;
    }

We create a MultiPageWidgetExtensionFactory object that we register using Qt Designer's current extension manager retrieved from the QDesignerFormEditorInterface parameter. The first argument is the newly created factory and the second argument is an extension identifier which is a string. The Q_TYPEID() macro simply convert the string into a QLatin1String.

The MultiPageWidgetExtensionFactory class is a subclass of QExtensionFactory. When Qt Designer must know whether a widget is a container, or not, Qt Designer's extension manager will run through all its registered factories invoking the first one which is able to create a container extension for that widget. This factory will in turn create a MultiPageWidgetExtension object.

    QString MultiPageWidgetPlugin::domXml() const
    {
        return QString("\
        <widget class=\"MultiPageWidget\" name=\"multipagewidget\">\
            <widget class=\"QWidget\" />\
        </widget>\
        ");
    }

Note also the domXml() function which include default settings for the widget in the standard XML format used by Qt Designer. In this case, we specify the container's first page; any inital pages of a multi-page widget must be specified within this function.

We have omitted to reimplement the QDesignerCustomWidgetInterface::codeTemplate() function which normally provide a sample code template for the custom widget.

    Q_EXPORT_PLUGIN2(containerextension, MultiPageWidgetPlugin)

Finally, we use the Q_EXPORT_PLUGIN() macro to export the MultiPageWidgetPlugin class for use with Qt's plugin handling classes: This macro ensures that Qt Designer can access and construct the custom widget. Without this macro, there is no way for Qt Designer to use the widget.

MultiPageWidgetExtensionFactory Class Definition

The MultiPageWidgetExtensionFactory class inherits QExtensionFactory which provides a standard extension factory for Qt Designer.

    class MultiPageWidgetExtensionFactory: public QExtensionFactory
    {
        Q_OBJECT

    public:
        MultiPageWidgetExtensionFactory(QExtensionManager *parent = 0);

    protected:
        QObject *createExtension(QObject *object, const QString &iid, QObject *parent) const;
    };

The subclass's purpose is to reimplement the QExtensionFactory::createExtension() function, making it able to create a MultiPageWidget container extension.

MultiPageWidgetExtensionFactory Class Implementation

The class constructor simply calls the QExtensionFactory base class constructor:

    MultiPageWidgetExtensionFactory::MultiPageWidgetExtensionFactory(QExtensionManager *parent)
        : QExtensionFactory(parent)
    {}

As described above, the factory is invoked when Qt Designer must know whether the associated widget is a container, or not.

    QObject *MultiPageWidgetExtensionFactory::createExtension(QObject *object,
                                                              const QString &iid,
                                                              QObject *parent) const
    {
        MultiPageWidget *widget = qobject_cast<MultiPageWidget*>(object);

        if (widget && (iid == Q_TYPEID(QDesignerContainerExtension))) {
            return new MultiPageWidgetContainerExtension(widget, parent);
        } else {
            return 0;
        }
    }

Qt Designer's behavior is the same whether the requested extension is associated with a container, a member sheet, a property sheet or a task menu: Its extension manager runs through all its registered extension factories calling createExtension() for each until one responds by creating the requested extension.

So the first thing we do in MultiPageWidgetExtensionFactory::createExtension() is to check if the QObject, for which the extension is requested, is in fact a MultiPageWidget object. Then we check if the requested extension is a container extension.

If the object is a MultiPageWidget requesting a container extension, we create and return a MultiPageWidgetExtension object. Otherwise, we simply return a null pointer, allowing Qt Designer's extension manager to continue its search through the registered factories.

MultiPageWidgetContainerExtension Class Definition

The MultiPageWidgetContainerExtension class inherits QDesignerContainerExtension which allows you to add (and delete) pages to a multi-page container plugin in Qt Designer.

    class MultiPageWidgetContainerExtension: public QObject,
                                             public QDesignerContainerExtension
    {
        Q_OBJECT
        Q_INTERFACES(QDesignerContainerExtension)

    public:
        MultiPageWidgetContainerExtension(MultiPageWidget *widget, QObject *parent);

        void addWidget(QWidget *widget);
        int count() const;
        int currentIndex() const;
        void insertWidget(int index, QWidget *widget);
        void remove(int index);
        void setCurrentIndex(int index);
        QWidget *widget(int index) const;

    private:
        MultiPageWidget *myWidget;
    };

It is important to recognize that the QDesignerContainerExtension class only is intended to provide Qt Designer access to your custom multi-page widget's functionality; your custom multi-page widget must implement functionality corresponding to the extension's functions.

Note also that we implement a constructor that takes two arguments: the parent widget, and the MultiPageWidget object for which the task menu is requested.

QDesignerContainerExtension provides a couple of menu entries in Qt Designer's task menu by default, enabling the user to add or delete pages to the associated custom multi-page widget in Qt Designer's workspace.

MultiPageWidgetContainerExtension Class Implementation

In the constructor we save the reference to the MultiPageWidget object sent as parameter, i.e the widget associated with the extension. We will need this later to access the custom multi-page widget performing the requested actions.

    MultiPageWidgetContainerExtension::MultiPageWidgetContainerExtension(MultiPageWidget *widget,
                                                                         QObject *parent)
        :QObject(parent)
    {
        myWidget = widget;
    }

To fully enable Qt Designer to manage and manipulate your custom multi-page widget, you must reimplement all the functions of QDesignerContainerExtension:

    void MultiPageWidgetContainerExtension::addWidget(QWidget *widget)
    {
        myWidget->addPage(widget);
    }

    int MultiPageWidgetContainerExtension::count() const
    {
        return myWidget->count();
    }

    int MultiPageWidgetContainerExtension::currentIndex() const
    {
        return myWidget->currentIndex();
    }

You must reimplement addWidget() adding a given page to the container, count() returning the number of pages in the container, and currentIndex() returning the index of the currently selected page.

    void MultiPageWidgetContainerExtension::insertWidget(int index, QWidget *widget)
    {
        myWidget->insertPage(index, widget);
    }

    void MultiPageWidgetContainerExtension::remove(int index)
    {
        myWidget->removePage(index);
    }

    void MultiPageWidgetContainerExtension::setCurrentIndex(int index)
    {
        myWidget->setCurrentIndex(index);
    }

    QWidget* MultiPageWidgetContainerExtension::widget(int index) const
    {
        return myWidget->widget(index);
    }

You must reimplement insertWidget() adding a given page to the container at a given index, remove() deleting the page at a given index, setCurrentIndex() setting the index of the currently selected page, and finally widget() returning the page at a given index.

MultiPageWidget Class Definition

The MultiPageWidget class is a custom container widget that lets the user manipulate and populate its pages, and navigate among these using a combobox.

    class MultiPageWidget : public QWidget
    {
        Q_OBJECT
        Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex)
        Q_PROPERTY(QString pageTitle READ pageTitle WRITE setPageTitle)

    public:
        MultiPageWidget(QWidget *parent = 0);

        QSize sizeHint() const;

        void addPage(QWidget *page);
        void removePage(int index);
        int count();
        int currentIndex();
        void insertPage(int index, QWidget *page);
        void setCurrentIndex(int index);
        QWidget *widget(int index);

        QString pageTitle() const;
        void setPageTitle(QString const &newTitle);

    private:
        QStackedWidget *stackWidget;
        QComboBox *comboBox;
        QVBoxLayout *layout;
    };

The main detail to observe is that your custom multi-page widget must implement functionality corresponding to the QDesignerContainerExtension's member functions since the QDesignerContainerExtension class only is intended to provide Qt Designer access to your custom multi-page widget's functionality.

In addition, we declare the currentIndex and pageTitle properties, and their associated set and get functions. By declaring these attributes as properties, we allow Qt Designer to manage them in the same way it manages the properties the MultiPageWidget widget inherits from QWidget and QObject, for example featuring the property editor.


Copyright © 2005 Trolltech Trademarks
Qt 4.1.0
Hosted by uCoz