Difference between revisions of "Development/Tutorials/Writing Qt Designer Plugins"

Jump to: navigation, search
(The interface to the plugin)
(update to new syntaxhighlighter)
 
(12 intermediate revisions by one user not shown)
Line 1: Line 1:
 
== Abstract ==
 
== Abstract ==
  
This tutorial shows how to add support for custom GUI elements to Qt Designer. It starts by showing how to add a simple custom widget.
+
This tutorial shows how to add support for custom GUI elements to Qt Designer. In the first section you learn how to write a Qt Designer plugin for a simple custom widget. The second section then presents how to support more than one widget in a plugin.
  
 
+
== Creating a simple Plugin for a custom Widget ==
== Creating a simple factory for a custom widget ==
+
  
 
We assume you have written a nice widget which you also want to be able to use in Qt Designer and the ui files. For this to achieve you have to write a plugin module for Qt Designer. It consists of just a single object of a class you have to write.  
 
We assume you have written a nice widget which you also want to be able to use in Qt Designer and the ui files. For this to achieve you have to write a plugin module for Qt Designer. It consists of just a single object of a class you have to write.  
  
=== The interface to the plugin ===
+
=== The Interface to the Plugin ===
The class, a factory, needs to be subclassed from {{qt|QObject}} and to implement the interface {{qt|QDesignerCustomWidgetInterface}}, as given by example for the widget MyWidget in the "mywidgetdesignerfactory.h":
+
The class, a factory, needs to be subclassed from {{qt|QObject}} and to implement the interface {{qt|QDesignerCustomWidgetInterface}}, as given by example for the widget MyWidget in the file "mywidgetdesignerfactory.h":
  
<code cppqt n>
+
<syntaxhighlight lang="cpp-qt" line="">
 
#ifndef MYWIDGETDESIGNERFACTORY_H
 
#ifndef MYWIDGETDESIGNERFACTORY_H
 
#define MYWIDGETDESIGNERFACTORY_H
 
#define MYWIDGETDESIGNERFACTORY_H
Line 17: Line 16:
 
// Qt
 
// Qt
 
#include <QtDesigner/QDesignerCustomWidgetInterface>
 
#include <QtDesigner/QDesignerCustomWidgetInterface>
 +
#include <QtCore/QObject>
  
 
class MyWidgetDesignerFactory : public QObject, public QDesignerCustomWidgetInterface
 
class MyWidgetDesignerFactory : public QObject, public QDesignerCustomWidgetInterface
Line 24: Line 24:
  
 
   public:
 
   public:
     explicit MyWidgetDesignerFactory : QObject* parent = 0 );
+
     explicit MyWidgetDesignerFactory( QObject* parent = 0 );
  
 
   public: // QDesignerCustomWidgetInterface API
 
   public: // QDesignerCustomWidgetInterface API
Line 38: Line 38:
  
 
#endif
 
#endif
</code>
+
</syntaxhighlight>
  
=== Creating the data as needed by the interface ===
+
=== Creating the Data as needed by the Interface ===
  
 
The definition of the methods is done as shown in the file "mywidgetdesignerfactory.cpp":
 
The definition of the methods is done as shown in the file "mywidgetdesignerfactory.cpp":
  
<code cppqt n>
+
<syntaxhighlight lang="cpp-qt" line="">
 
#include "mywidgetdesignerfactory.h"
 
#include "mywidgetdesignerfactory.h"
  
Line 103: Line 103:
 
// export macro, takes the name of the plugin module and the class name
 
// export macro, takes the name of the plugin module and the class name
 
Q_EXPORT_PLUGIN2( mydesignerplugin, MyWidgetDesignerFactory )
 
Q_EXPORT_PLUGIN2( mydesignerplugin, MyWidgetDesignerFactory )
 +
</syntaxhighlight>
  
</code>
+
For detailed information about the purpose of all the methods of the API you might want to read [http://qt.nokia.com/doc/designer-creating-custom-widgets.html the related page] from the Qt documentation.
  
 
=== Adding to the Buildsystem ===
 
=== Adding to the Buildsystem ===
  
After you created the two files above you need to tell the buildsystem how to create the Qt Designer plugin and where to install it. This needs a CMakeLists.txt file in the same directory with such content:
+
After you created the two files above you need to tell the buildsystem how to build the Qt Designer plugin from them and where to install it. This needs a CMakeLists.txt file in the same directory with such content:
 +
 
 +
<syntaxhighlight lang="cmake">
 +
set( mydesignerplugin_SRCS
 +
  mywidgetdesignerfactory.cpp
 +
)
 +
 
 +
# the name of the plugin module is the same name as used in the macro Q_EXPORT_PLUGIN2 in the file mywidgetdesignerfactory.cpp
 +
kde4_add_plugin( mydesignerplugin  ${mydesignerplugin_SRCS} )
 +
 
 +
target_link_libraries( mydesignerplugin
 +
  mylib
 +
  # other needed libs
 +
)
 +
 
 +
install( TARGETS mydesignerplugin  DESTINATION ${PLUGIN_INSTALL_DIR}/plugins/designer )
 +
</syntaxhighlight>
 +
 
 +
=== Finding your Widget in Qt Designer ===
 +
If you successfully compiled and installed your plugin, (re-)start Qt Designer and have a look in the Widgetbox (on the left side by default). If everything worked perfectly you will see a new entry "MyNamespace::MyWidget" (as defined by <tt>MyWidgetDesignerFactory::name()</tt>) in the group "Some group (KDE)" (as defined by <tt>MyWidgetDesignerFactory::group()</tt>). Now drag and drop the entry to the currently edited view in Qt Designer, and voilà, your widget should be added to that view.
 +
 
 +
 
 +
== Creating a Bundle Plugin for several Widgets ==
 +
 
 +
You may have created not just one, but several widgets which you would like to enable support for in Qt Designer. Instead of writing a plugin for each widget you can collect the factories for all widgets in a single plugin, by using a helper class.
 +
 
 +
In the next subsections it is assumed you have already written factories for your two widgets <tt>MyWidget</tt> and <tt>MyOtherWidget</tt> as described in the previous section, namely <tt>MyWidgetDesignerFactory</tt> and <tt>MyOtherWidgetDesignerFactory</tt>, using the headers "mywidgetdesignerfactory.h" and "myotherwidgetdesignerfactory.h" and the implementation files "mywidgetdesignerfactory.cpp" and "myotherwidgetdesignerfactory.cpp".
 +
 
 +
=== The Interface to the Bundle ===
 +
 
 +
The helper class, which is used to hold all factories, needs to be subclassed from {{qt|QObject}} and to implement the interface {{qt|QDesignerCustomWidgetCollectionInterface}}, as in the following example MyWidgetDesignerFactoryCollection in the file "mywidgetdesignerfactorycollection.h":
 +
 
 +
<syntaxhighlight lang="cpp-qt" line="">
 +
#ifndef MYWIDGETDESIGNERFACTORYCOLLECTION_H
 +
#define MYWIDGETDESIGNERFACTORYCOLLECTION_H
 +
 
 +
// Qt
 +
#include <QtDesigner/QDesignerCustomWidgetCollectionInterface>
 +
#include <QtCore/QObject>
 +
 
 +
class MyWidgetDesignerFactoryCollection : public QObject, public QDesignerCustomWidgetCollectionInterface
 +
{
 +
  Q_OBJECT
 +
  Q_INTERFACES( QDesignerCustomWidgetCollectionInterface
 +
 
 +
  public:
 +
    explicit MyWidgetDesignerFactoryCollection( QObject* parent = 0 );
 +
 
 +
  public: // QDesignerCustomWidgetCollectionInterface API
 +
    virtual QList<QDesignerCustomWidgetInterface*> customWidgets() const;
 +
 
 +
  private:
 +
    QList<QDesignerCustomWidgetInterface*> mWidgetFactories;
 +
};
 +
 
 +
#endif
 +
</syntaxhighlight>
 +
 
 +
 
 +
=== Putting the Factories into the Collection  ===
 +
 
 +
The implementation of the helper class is pretty simple. You just have to create all widget factories in the constructor and add them to the list member. This list is then returned in the method <tt>MyWidgetDesignerFactoryCollection::customWidgets()</tt>. See the example code of the file "mywidgetdesignerfactorycollection.cpp":
 +
 
 +
<syntaxhighlight lang="cpp-qt" line="">
 +
#include "mywidgetdesignerfactorycollection.h"
 +
 
 +
// plugin
 +
#include "mywidgetdesignerfactory.h"
 +
#include "myotherwidgetdesignerfactory.h"
 +
// Qt
 +
#include <QtCore/QtPlugin>
 +
 
 +
MyWidgetDesignerFactoryCollection::MyWidgetDesignerFactoryCollection( QObject* parent )
 +
  : QObject( parent )
 +
{
 +
    mWidgetFactories.append( new MyWidgetDesignerFactory(this) );
 +
    mWidgetFactories.append( new MyOtherWidgetDesignerFactory(this) );
 +
}
 +
 
 +
QList<QDesignerCustomWidgetInterface*> MyWidgetDesignerFactoryCollection::customWidgets() const
 +
{
 +
    return mWidgetFactories;
 +
}
 +
 
 +
Q_EXPORT_PLUGIN2( mydesignerplugin, MyWidgetDesignerFactoryCollection )
 +
</syntaxhighlight>
 +
 
 +
Important: As the <tt>MyWidgetDesignerFactoryCollection</tt> is now the central class of the plugin and not any of the widget factories, the source files of the widget factories should no more contain the macro <tt>Q_EXPORT_PLUGIN2</tt>. Otherwise the build will fail.
 +
 
 +
=== Adapting the Buildsystem ===
  
set( mydesignerplugin_SRCS
+
The CMakeLists.txt content is similar to the one for the single widget factory plugin. The two differences are in the files listed for <tt>mydesignerplugin_SRCS</tt>, here you put all the source files of the factories and the one of the helper class, and the libraries listed in <tt>target_link_libraries( ... )</tt>, here you collect all libraries as needed by the single widget factories:
  mywidgetdesignerfactory.cpp
+
)
+
  
# the name of the plugin module is the same name as used in the macro Q_EXPORT_PLUGIN2 in the mywidgetdesignerfactory.cpp file
+
<syntaxhighlight lang="cmake">
kde4_add_plugin( mydesignerplugin  ${mydesignerplugin_SRCS} )
+
set( mydesignerplugin_SRCS
 +
  mywidgetdesignerfactory.cpp
 +
  myotherwidgetdesignerfactory.cpp
 +
  # and any other factory source file
 +
  mywidgetdesignerfactorycollection.cpp
 +
)
  
target_link_libraries( mydesignerplugin
+
# the name of the plugin module is the same name as used in the macro Q_EXPORT_PLUGIN2 in the file mywidgetdesignerfactorycollection.cpp
  mylib
+
kde4_add_plugin( mydesignerplugin  ${mydesignerplugin_SRCS} )
  # other needed libs
+
  )
+
  
install( TARGETS mydesignerplugin DESTINATION ${PLUGIN_INSTALL_DIR}/plugins/designer )
+
target_link_libraries( mydesignerplugin
 +
  mylib
 +
  # other needed libs
 +
)
  
 +
install( TARGETS mydesignerplugin  DESTINATION ${PLUGIN_INSTALL_DIR}/plugins/designer )
 +
</syntaxhighlight>
  
=== Finding your widget in Qt Designer ===
+
Now if you compile and install this new bundle plugin, after the (re-)start of Qt Designer you should find all your widgets in the Widgetbox. Make sure you have removed any previously installed plugins with a single widget factory for any of the widgets before to avoid conflicts.
If you successfully compiled and installed your plugin, (re-)start Qt Designer and have a look in the Widgetbox (on the left side by default). If everything worked perfectly you will see a new entry "MyNamespace::MyWidget" (as defined by MyWidgetDesignerFactory::name()) in the group "Some group (KDE)" (as defined by MyWidgetDesignerFactory::group()). Now drag and drop the entry to the currently edited view in Qt Designer, and voilà, it should be added to the view.
+

Latest revision as of 20:44, 29 June 2011

Contents

[edit] Abstract

This tutorial shows how to add support for custom GUI elements to Qt Designer. In the first section you learn how to write a Qt Designer plugin for a simple custom widget. The second section then presents how to support more than one widget in a plugin.

[edit] Creating a simple Plugin for a custom Widget

We assume you have written a nice widget which you also want to be able to use in Qt Designer and the ui files. For this to achieve you have to write a plugin module for Qt Designer. It consists of just a single object of a class you have to write.

[edit] The Interface to the Plugin

The class, a factory, needs to be subclassed from QObject and to implement the interface QDesignerCustomWidgetInterface, as given by example for the widget MyWidget in the file "mywidgetdesignerfactory.h":

  1. #ifndef MYWIDGETDESIGNERFACTORY_H
  2. #define MYWIDGETDESIGNERFACTORY_H
  3.  
  4. // Qt
  5. #include <QtDesigner/QDesignerCustomWidgetInterface>
  6. #include <QtCore/QObject>
  7.  
  8. class MyWidgetDesignerFactory : public QObject, public QDesignerCustomWidgetInterface
  9. {
  10.   Q_OBJECT
  11.   Q_INTERFACES( QDesignerCustomWidgetInterface )
  12.  
  13.   public:
  14.     explicit MyWidgetDesignerFactory( QObject* parent = 0 );
  15.  
  16.   public: // QDesignerCustomWidgetInterface API
  17.     virtual QWidget* createWidget( QWidget* parent );
  18.     virtual QString group() const;
  19.     virtual QIcon icon() const;
  20.     virtual QString includeFile() const;
  21.     virtual bool isContainer() const;
  22.     virtual QString name() const;
  23.     virtual QString toolTip() const;
  24.     virtual QString whatsThis() const;
  25. };
  26.  
  27. #endif

[edit] Creating the Data as needed by the Interface

The definition of the methods is done as shown in the file "mywidgetdesignerfactory.cpp":

  1. #include "mywidgetdesignerfactory.h"
  2.  
  3. // my lib
  4. #include <mywidget.h>
  5. // Qt
  6. #include <QtCore/QtPlugin>
  7.  
  8.  
  9. MyWidgetDesignerFactory::MyWidgetDesignerFactory( QObject* parent )
  10.   : QObject( parent )
  11. {
  12. }
  13.  
  14. QWidget* MyWidgetDesignerFactory::createWidget( QWidget* parent )
  15. {
  16.     MyNamespace::MyWidget* widget = new MyNamespace::MyWidget( parent );
  17.     // init with some example data useful in the preview inside Qt Designer
  18.     // this data will be only used there, not in the resulting view in the program.
  19.     return widget;
  20. }
  21.  
  22. QString MyWidgetDesignerFactory::group() const
  23. {
  24.     return QString::fromLatin1("Some group (KDE)");
  25. }
  26.  
  27. QIcon MyWidgetDesignerFactory::icon() const
  28. {
  29.     return QIcon();
  30. }
  31.  
  32. QString MyWidgetDesignerFactory::includeFile() const
  33. {
  34.     return QString::fromLatin1("neededincludepathprefix/mywidget.h");
  35. }
  36.  
  37. QString MyWidgetDesignerFactory::toolTip() const
  38. {
  39.     return QString::fromLatin1("Useful Widget of Mine");
  40. }
  41.  
  42. QString MyWidgetDesignerFactory::whatsThis() const
  43. {
  44.     return QString::fromLatin1("Some description of my widget.");
  45. }
  46.  
  47. bool MyWidgetDesignerFactory::isContainer() const
  48. {
  49.     return false;
  50. }
  51.  
  52. QString MyWidgetDesignerFactory::name() const
  53. {
  54.     return QString::fromLatin1("MyNamespace::MyWidget");
  55. }
  56.  
  57. // export macro, takes the name of the plugin module and the class name
  58. Q_EXPORT_PLUGIN2( mydesignerplugin, MyWidgetDesignerFactory )

For detailed information about the purpose of all the methods of the API you might want to read the related page from the Qt documentation.

[edit] Adding to the Buildsystem

After you created the two files above you need to tell the buildsystem how to build the Qt Designer plugin from them and where to install it. This needs a CMakeLists.txt file in the same directory with such content:

set( mydesignerplugin_SRCS
  mywidgetdesignerfactory.cpp
)
 
# the name of the plugin module is the same name as used in the macro Q_EXPORT_PLUGIN2 in the file mywidgetdesignerfactory.cpp
kde4_add_plugin( mydesignerplugin  ${mydesignerplugin_SRCS} )
 
target_link_libraries( mydesignerplugin
  mylib
  # other needed libs
)
 
install( TARGETS mydesignerplugin  DESTINATION ${PLUGIN_INSTALL_DIR}/plugins/designer )

[edit] Finding your Widget in Qt Designer

If you successfully compiled and installed your plugin, (re-)start Qt Designer and have a look in the Widgetbox (on the left side by default). If everything worked perfectly you will see a new entry "MyNamespace::MyWidget" (as defined by MyWidgetDesignerFactory::name()) in the group "Some group (KDE)" (as defined by MyWidgetDesignerFactory::group()). Now drag and drop the entry to the currently edited view in Qt Designer, and voilà, your widget should be added to that view.


[edit] Creating a Bundle Plugin for several Widgets

You may have created not just one, but several widgets which you would like to enable support for in Qt Designer. Instead of writing a plugin for each widget you can collect the factories for all widgets in a single plugin, by using a helper class.

In the next subsections it is assumed you have already written factories for your two widgets MyWidget and MyOtherWidget as described in the previous section, namely MyWidgetDesignerFactory and MyOtherWidgetDesignerFactory, using the headers "mywidgetdesignerfactory.h" and "myotherwidgetdesignerfactory.h" and the implementation files "mywidgetdesignerfactory.cpp" and "myotherwidgetdesignerfactory.cpp".

[edit] The Interface to the Bundle

The helper class, which is used to hold all factories, needs to be subclassed from QObject and to implement the interface QDesignerCustomWidgetCollectionInterface, as in the following example MyWidgetDesignerFactoryCollection in the file "mywidgetdesignerfactorycollection.h":

  1. #ifndef MYWIDGETDESIGNERFACTORYCOLLECTION_H
  2. #define MYWIDGETDESIGNERFACTORYCOLLECTION_H
  3.  
  4. // Qt
  5. #include <QtDesigner/QDesignerCustomWidgetCollectionInterface>
  6. #include <QtCore/QObject>
  7.  
  8. class MyWidgetDesignerFactoryCollection : public QObject, public QDesignerCustomWidgetCollectionInterface
  9. {
  10.   Q_OBJECT
  11.   Q_INTERFACES( QDesignerCustomWidgetCollectionInterface
  12.  
  13.   public:
  14.     explicit MyWidgetDesignerFactoryCollection( QObject* parent = 0 );
  15.  
  16.   public: // QDesignerCustomWidgetCollectionInterface API
  17.     virtual QList<QDesignerCustomWidgetInterface*> customWidgets() const;
  18.  
  19.   private:
  20.     QList<QDesignerCustomWidgetInterface*> mWidgetFactories;
  21. };
  22.  
  23. #endif


[edit] Putting the Factories into the Collection

The implementation of the helper class is pretty simple. You just have to create all widget factories in the constructor and add them to the list member. This list is then returned in the method MyWidgetDesignerFactoryCollection::customWidgets(). See the example code of the file "mywidgetdesignerfactorycollection.cpp":

  1. #include "mywidgetdesignerfactorycollection.h"
  2.  
  3. // plugin
  4. #include "mywidgetdesignerfactory.h"
  5. #include "myotherwidgetdesignerfactory.h"
  6. // Qt
  7. #include <QtCore/QtPlugin>
  8.  
  9. MyWidgetDesignerFactoryCollection::MyWidgetDesignerFactoryCollection( QObject* parent )
  10.   : QObject( parent )
  11. {
  12.      mWidgetFactories.append( new MyWidgetDesignerFactory(this) );
  13.      mWidgetFactories.append( new MyOtherWidgetDesignerFactory(this) );
  14. }
  15.  
  16. QList<QDesignerCustomWidgetInterface*> MyWidgetDesignerFactoryCollection::customWidgets() const
  17. {
  18.     return mWidgetFactories;
  19. }
  20.  
  21. Q_EXPORT_PLUGIN2( mydesignerplugin, MyWidgetDesignerFactoryCollection )

Important: As the MyWidgetDesignerFactoryCollection is now the central class of the plugin and not any of the widget factories, the source files of the widget factories should no more contain the macro Q_EXPORT_PLUGIN2. Otherwise the build will fail.

[edit] Adapting the Buildsystem

The CMakeLists.txt content is similar to the one for the single widget factory plugin. The two differences are in the files listed for mydesignerplugin_SRCS, here you put all the source files of the factories and the one of the helper class, and the libraries listed in target_link_libraries( ... ), here you collect all libraries as needed by the single widget factories:

set( mydesignerplugin_SRCS
  mywidgetdesignerfactory.cpp
  myotherwidgetdesignerfactory.cpp
  # and any other factory source file
  mywidgetdesignerfactorycollection.cpp
)
 
# the name of the plugin module is the same name as used in the macro Q_EXPORT_PLUGIN2 in the file mywidgetdesignerfactorycollection.cpp
kde4_add_plugin( mydesignerplugin  ${mydesignerplugin_SRCS} )
 
target_link_libraries( mydesignerplugin
  mylib
  # other needed libs
)
 
install( TARGETS mydesignerplugin  DESTINATION ${PLUGIN_INSTALL_DIR}/plugins/designer )

Now if you compile and install this new bundle plugin, after the (re-)start of Qt Designer you should find all your widgets in the Widgetbox. Make sure you have removed any previously installed plugins with a single widget factory for any of the widgets before to avoid conflicts.


This page was last modified on 29 June 2011, at 20:44. This page has been accessed 11,453 times. Content is available under Creative Commons License SA 3.0 as well as the GNU Free Documentation License 1.2.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V.Legal