4.3.4. Plugin WAF Module
At this point, the project needs to be extended. The new widget-library/plugin
module is added
as shown in the following listing:
widget-library
├── plugin
│ ├── src
│ │ ├── include
│ │ │ └── cut
│ │ │ └── examples
│ │ │ └── widgets
│ │ │ └── plugin
│ │ │ ├── QeExampleDmsLabelPlugin.hpp
│ │ │ └── QeExamplesWidgetCollection.hpp
│ │ ├── QeExampleDmsLabelPlugin.cpp
│ │ └── QeExamplesWidgetCollection.cpp
│ └── wscript
├── widgets
│ ├── src
│ │ ├── include
│ │ │ ├── cut
│ │ │ │ └── examples
│ │ │ │ └── widgets
│ │ │ │ └── widgets
│ │ │ │ └── QeExampleDmsLabel.hpp
│ │ │ └── QeExamplesWidgets.h
│ │ └── QeExampleDmsLabel.cpp
│ └── wscript
└── wscript
The plugin/wscript
file looks a bit different than the one in widgets
WAF module:
1from wtools.module import declare_qtcshlib
2
3# In the "use" parameter, if using modules from the same project,
4# you should use the name of the directory. It can be different from
5# the name of the target of that directory.
6declare_qtcshlib(
7 target='cutExamplesWidgetsPlugin',
8 use='widgets',
9 qt5_plugin=True
10)
This wscript file also uses the declare_qtcshlib wtools instruction. The main difference here is
the additional keyword argument qt_plugin=True
. This will indicate to the install command
that the resulting library should be place into $INTROOT/lib64/designer
. Then the
QT_PLUGIN_PATH
environment variable can be used by Qt Designer to find any widgets plugin.
QT_PLUGIN_PATH
shall be $INTROOT/lib64
, as the designer expects a certain directory
structure. One of these directories is designer
, which is the one used to store any plugin
intended for Qt Designer.
The second different is that the use
argument for declare_qtcshlib command now include
widgets
. This indicates WAF that widgets
module is a dependency, and therefore, must be
compiled before this module. Also, when compiling this plugin
module, its includes added to
include paths, and its library added for linking instructions. widgets
string must be the names
of the directory structure, not the target names. If many directory levels are used in the project,
then replace /
with .
.
Also, the installation instruction does not copy the includes from this module to the $INTROOT
.
As the plugins are not intended to be used for development, these files are not meant for further
development.
4.3.4.1. Header files
Two classes, one for QeExampleDmsLabel plugin, and another for a Collection, are defined in this module.
The listing of the QeExampleDmsLabelPlugin.hpp is given below:
1/**
2 * @file
3 * @ingroup widgets_plugin
4 * @copyright ESO - European Southern Observatory
5 * @author Arturo Hoffstadt Urrutia <ahoffsta@eso.org>
6 *
7 * @brief QeDmsLabel plugin for Qt Designer
8 */
9
10#ifndef QEEXAMPLEDMSLABELPLUGIN_HPP
11#define QEEXAMPLEDMSLABELPLUGIN_HPP
12
13#include <QtUiPlugin/QDesignerCustomWidgetInterface>
14
15/**
16 * @brief QeExampleDmsLabel Plugin for Qt Designer. Enables WYSIWYG design while using
17 * Qt Designer.
18 * @class QeExampleDmsLabelPlugin
19 * @ingroup widgets_plugin
20 *
21 * This class implements the QDesignerCustomWidgetInterface that enables
22 * Qt Designer to create new instances of the QeDmsLabel widget, and obtain
23 * information to present the widget, in the WYSIWYG view of the form, its
24 * toolbar, and properties view.
25 *
26 * @warning This class is not intended for developers, and is internal to CUT.
27 */
28class QeExampleDmsLabelPlugin : public QObject, public QDesignerCustomWidgetInterface
29{
30 Q_OBJECT
31 Q_INTERFACES(QDesignerCustomWidgetInterface)
32
33public:
34 QeExampleDmsLabelPlugin(QObject *parent = 0);
35
36 bool isContainer() const;
37 bool isInitialized() const;
38 QIcon icon() const;
39 QString domXml() const;
40 QString group() const;
41 QString includeFile() const;
42 QString name() const;
43 QString toolTip() const;
44 QString whatsThis() const;
45 QWidget *createWidget(QWidget *parent);
46 void initialize(QDesignerFormEditorInterface *core);
47
48private:
49 bool m_initialized;
50};
51
52#endif // QEEXAMPLEDMSLABELPLUGIN_HPP
This file does not change much from widget to widget. Only the name of the class does which is used for Class name, and constructor.
The contents of the Collection are also not very dynamic:
1#ifndef QEEXAMPLEWIDGETCOLLECTION_HPP
2#define QEEXAMPLEWIDGETCOLLECTION_HPP
3
4#include <QtUiPlugin/QDesignerCustomWidgetInterface>
5#include <qplugin.h>
6
7class QeExamplesWidgetCollection : public QObject, public QDesignerCustomWidgetCollectionInterface
8{
9 Q_OBJECT
10 Q_INTERFACES(QDesignerCustomWidgetCollectionInterface)
11#if QT_VERSION >= 0x050000
12 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QDesignerCustomWidgetCollectionInterface")
13#endif // QT_VERSION >= 0x050000
14
15public:
16 explicit QeExamplesWidgetCollection(QObject *parent = 0);
17
18 virtual QList<QDesignerCustomWidgetInterface*> customWidgets() const;
19
20private:
21 QList<QDesignerCustomWidgetInterface*> m_widgets;
22};
23
24#endif // QEEXAMPLEWIDGETCOLLECTION_HPP
The name of this class is tied to the name of the library instead of a particular widget. This Collection will provide access to all widgets in the plugin. The matter that we only provide only changes nothing. Qt Designer provides to us an interface ready to use to extend it with more widgets.
4.3.4.2. Implementation
The plugin implementation has more details. The Collection implementation needs to add the Plugin classes to a list during construction. And a specific method returns the list, informing Qt Designer of the widgets included in this Collection.
1#include "include/cut/examples/widgets/plugin/QeExamplesWidgetCollection.hpp"
2#include "include/cut/examples/widgets/plugin/QeExampleDmsLabelPlugin.hpp"
3
4#if WAF
5#include "include/cut/examples/widgets/plugin/QeExamplesWidgetCollection.moc"
6#endif
7
8
9QeExamplesWidgetCollection::QeExamplesWidgetCollection(QObject *parent)
10 : QObject(parent)
11{
12 m_widgets.append(new QeExampleDmsLabelPlugin(this));
13}
14
15QList<QDesignerCustomWidgetInterface*> QeExamplesWidgetCollection::customWidgets() const
16{
17 return m_widgets;
18}
The Plugin implementation itself deals with necessary entries used during code generation. The UI files are themselves XML, and every time a widget is added to a UI file using the Qt Designer, it will query the different methods from this implementation.
1#include "cut/examples/widgets/widgets/QeExampleDmsLabel.hpp"
2#include "include/cut/examples/widgets/plugin/QeExampleDmsLabelPlugin.hpp"
3
4#include <QtPlugin>
5
6#if WAF
7#include "include/cut/examples/widgets/plugin/QeExampleDmsLabelPlugin.moc"
8#endif
9
10QeExampleDmsLabelPlugin::QeExampleDmsLabelPlugin(QObject *parent)
11 : QObject(parent)
12{
13 m_initialized = false;
14}
15
16void QeExampleDmsLabelPlugin::initialize(QDesignerFormEditorInterface * /* core */)
17{
18 if (m_initialized)
19 return;
20
21 // Add extension registrations, etc. here
22
23 m_initialized = true;
24}
25
26bool QeExampleDmsLabelPlugin::isInitialized() const
27{
28 return m_initialized;
29}
30
31QWidget *QeExampleDmsLabelPlugin::createWidget(QWidget *parent)
32{
33 return new QeExampleDmsLabel(parent);
34}
35
36QString QeExampleDmsLabelPlugin::name() const
37{
38 return QLatin1String("QeExampleDmsLabel");
39}
40
41QString QeExampleDmsLabelPlugin::group() const
42{
43 return QLatin1String("Display Widgets");
44}
45
46QIcon QeExampleDmsLabelPlugin::icon() const
47{
48 return QIcon();
49}
50
51QString QeExampleDmsLabelPlugin::toolTip() const
52{
53 return QLatin1String("Displays as Degrees-Minutes-Seconds, or Hour-Minutes-Seconds, an angle in radians.");
54}
55
56QString QeExampleDmsLabelPlugin::whatsThis() const
57{
58 return QLatin1String("");
59}
60
61bool QeExampleDmsLabelPlugin::isContainer() const
62{
63 return false;
64}
65
66QString QeExampleDmsLabelPlugin::domXml() const
67{
68 return QLatin1String("<widget class=\"QeExampleDmsLabel\" name=\"qeExampleDmsLabel\">\n"
69 " <property name=\"radians\">\n"
70 " <double>0.0</double>\n"
71 " </property>\n"
72 " <property name=\"precision\">\n"
73 " <number>3</number>\n"
74 " </property>\n"
75 "</widget>\n");
76}
77
78/*
79 * We use a small hack to allow compatibility between Python
80 * and C++ resolution of classes on the UI compilers.
81 * C++ UI compiler uses the includeFile() to construct its
82 * include statement.
83 *
84 * #include QeWidgetExample.h
85 * QeDartBoard* qeDartBoard = new QeDartBoard();
86 *
87 * Python UI compiler uses the includeFile() and the name()
88 * to construct the import statement, but removes the '.h'
89 * suffix.
90 *
91 * from QeWidgetExample import QeDartBoard
92 *
93 * Using an intermediary file allows us to use the same
94 * includeFile() string under Python and C++.
95 */
96QString QeExampleDmsLabelPlugin::includeFile() const
97{
98 return QLatin1String("QeExamplesWidgets.h");
99}
100
101////
createWidget()
should return a new widget. This is used by the designer to place a widget in the view for the WYSIWYG editor.name()
returns the class name of the widget. It has to be the name of the class in C++/Python.group()
returns a name for the category the widget is placed in the Qt Designer Toolbox.icon()
returns a Pixmap that represents the widget in a concise manner. Used in the Toolbox along with the :samp`name`, and in the Object Inspector Docking Widget.toolTip()
contextual help shown as a tooltip on the Toolbox.whatsThis()
contextual help shown when the What’s This feature is activated. Usually is longer than the tooltip.domXml()
initial XML inserted into the UI file when the widget is added to the file.