Difference between revisions of "Slicer3:Developers:Projects:QtSlicer/Tutorials/WidgetWriting"

From Slicer Wiki
Jump to: navigation, search
(Add a tutorial to add custom widgets in Slicer)
 
Line 11: Line 11:
 
==Before starting==
 
==Before starting==
 
There are 2 directories where custom widgets can be. You first have to decide in what directory your custom widget should go:
 
There are 2 directories where custom widgets can be. You first have to decide in what directory your custom widget should go:
*Slicer3/Lib/QCTKWidgets: Qt only widget
+
*Slicer3/Libs/qCTKWidgets: Qt only widget
*Slicer3/Lib/QMRMLWidgets: MRML-aware widgets
+
*Slicer3/Libs/qMRMLWidgets: MRML-aware widgets
 
A good practice is to split (if possible) your custom widget in 2 widgets, a QT only widget, and a MRML-aware widget. The MRML widget inherits from the Qt only widget.<br>
 
A good practice is to split (if possible) your custom widget in 2 widgets, a QT only widget, and a MRML-aware widget. The MRML widget inherits from the Qt only widget.<br>
 
It is important to keep the widgets basic. If you think someone else can use your custom widget differently, or if someone would need less features that the custom widget currently have, it is probably a good idea to split the widget in a main widget and a more specialized widget.<br>
 
It is important to keep the widgets basic. If you think someone else can use your custom widget differently, or if someone would need less features that the custom widget currently have, it is probably a good idea to split the widget in a main widget and a more specialized widget.<br>
Line 21: Line 21:
 
==Note==
 
==Note==
 
*When you create your widget, make sure you highly use the [Qt property system], it allows a great customization of your widget in the Qt Designer.  
 
*When you create your widget, make sure you highly use the [Qt property system], it allows a great customization of your widget in the Qt Designer.  
*As the process to create a custom widget is similar for QCTKWidgets and QMRMLWidgets, we will use in the following the notation <b>Q***Widgets</b> to describe either QCTKWidgets or QMRMLWidgets.
+
*As the process to create a custom widget is similar for qCTKWidgets and qMRMLWidgets, we will use in the following the notation <b>q***Widgets</b> to describe either qCTKWidgets or qMRMLWidgets.
  
 
==Step by step==
 
==Step by step==
*Create your widget files (.h and .cxx) in the Slicer3/Lib/Q***Widgets directory.
+
*Create your widget files (.h and .cxx) in the <i>Lib/q***Widgets directory</i>.
**If you use an .ui file, add it in the Slicer3/Lib/Q***Widgets/Resources/UI directory
+
**If you use an .ui file, add it in the <i>Libs/Q***Widgets/Resources/UI</i> directory
**If you use icon files, add them in the Slicer3/Lib/Q***Widgets/Resources/Icons directory and update the Lib/Q***Widgets/Resources/q***Widgets.qrc file  
+
**If you use icon files, add them in the <i>Libs/Q***Widgets/Resources/Icons</i> directory and update the <i>Libs/q***Widgets/Resources/q***Widgets.qrc</i> file  
*Update the Slicer3/Lib/Q***Widgets/CMakeLists.txt file with your widget files.
+
*Update the <i>Libs/q***Widgets/CMakeLists.txt</i> file with your widget files.
** add the .h and .cxx files in the Q***Widgets_SRCS variable
+
** add the .h and .cxx files in the q***Widgets_SRCS variable
** add the .h file in the QCTKWidgets_MOC_SRCS variable
+
** add the .h file in the q***Widgets_MOC_SRCS variable
** if any, add the .ui file in the Q***Widgets_UI_SRCS variable
+
** if any, add the .ui file in the q***Widgets_UI_SRCS variable
 
* compile
 
* compile
 
Congratulations, you just added a custom widget in Slicer. The widget can now be used anywhere in Slicer.<br>
 
Congratulations, you just added a custom widget in Slicer. The widget can now be used anywhere in Slicer.<br>
Line 37: Line 37:
 
For a presentation of creating custom widgets for Qt Designer, see http://doc.trolltech.com/designer-creating-custom-widgets.html
 
For a presentation of creating custom widgets for Qt Designer, see http://doc.trolltech.com/designer-creating-custom-widgets.html
 
==Step by step==
 
==Step by step==
*Copy paste this template in the Lib/Q***Widgets/Plugins directory.
+
*Copy paste this template in the <i>Libs/q***Widgets/Plugins</i> directory.
 
{|
 
{|
!QCTKWidget
+
!qCTKWidget
!QMRMLWidget
+
!qMRMLWidget
 
|-
 
|-
 
|<pre>
 
|<pre>
Line 46: Line 46:
 
#define __qCTKCustomWidgetPlugin_h
 
#define __qCTKCustomWidgetPlugin_h
  
#include "qCTKWidgetsPlugin.h"
+
#include "qCTKWidgetsBasePlugin.h"
 +
#include "qCTKWidgetsPluginWin32Header.h"
  
class qCTKCustomWidgetPlugin : public QObject,
+
class QCTK_WIDGETS_PLUGIN_EXPORT qCTKCustomWidgetPlugin : public QObject,
                              public qCTKWidgetsPlugin
+
                                                          public qCTKWidgetsBasePlugin
 
{
 
{
 
   Q_OBJECT
 
   Q_OBJECT
Line 67: Line 68:
  
 
</pre>
 
</pre>
Name the file qCTK[name of your widget]Plugin.h
+
Name the file <i>qCTK[name of your widget]Plugin.h</i>
 
|<pre>
 
|<pre>
 
#ifndef __qMRMLCustomWidgetPlugin_h
 
#ifndef __qMRMLCustomWidgetPlugin_h
 
#define __qMRMLCustomWidgetPlugin_h
 
#define __qMRMLCustomWidgetPlugin_h
  
#include "qMRMLWidgetsPlugin.h"
+
#include "qMRMLWidgetsBasePlugin.h"
 +
#include "qMRMLWidgetsPluginWin32Header.h"
  
class qMRMLCustomWidgetPlugin : public QObject,
+
class QMRML_WIDGETS_PLUGIN_EXPORT qMRMLCustomWidgetPlugin : public QObject,
                                 public qMRMLWidgetsPlugin
+
                                 public qMRMLWidgetsBasePlugin
 
{
 
{
 
   Q_OBJECT
 
   Q_OBJECT
Line 96: Line 98:
 
|}
 
|}
 
*Replace <i>CustomWidget</i> by the name of your widget
 
*Replace <i>CustomWidget</i> by the name of your widget
*Copy paste this template in the Lib/Q***Widgets/Plugins directory.
+
*Copy paste this template in the <i>Libs/q***Widgets/Plugins</i> directory.
 
{|
 
{|
!QCTKWidget
+
!qCTKWidgets
!QMRMLWidget
+
!qMRMLWidgets
 
|-
 
|-
 
|<pre>
 
|<pre>
Line 139: Line 141:
 
}
 
}
 
</pre>
 
</pre>
Name the file qCTK[name of your widget]Plugin.cxx
+
Name the file <i>qCTK[name of your widget]Plugin.cxx</i>
|<pre>
+
|<pre>#include "qMRMLCustomWidgetPlugin.h"
#include "qMRMLCustomWidgetPlugin.h"
 
 
#include "qMRMLCustomWidget.h"
 
#include "qMRMLCustomWidget.h"
  
Line 176: Line 177:
 
{
 
{
 
   return "qMRMLCustomWidget";
 
   return "qMRMLCustomWidget";
}
+
}</pre>
  
</pre>
 
 
Name the file qMRML[name of your widget]Plugin.cxx
 
Name the file qMRML[name of your widget]Plugin.cxx
 
|}
 
|}
 
*Replace <i>CustomWidget</i> by the name of your widget  
 
*Replace <i>CustomWidget</i> by the name of your widget  
*If the widget is a container, return true in the method isContainer(). See qCTKCollapsibleWidgetPlugin.cxx for more information.
+
*If the widget is a container, return true in the method <code>isContainer()</code>. See <i>qCTKCollapsibleWidgetPlugin.cxx</i> for more information.
*You can customize how the widget look in the designer by modifying the domxml() method.
+
*You can customize how the widget look in the designer by modifying the <code>domxml()</code> method.
*Update the Slicer3/Libs/Q***Widgets/Plugins/CMakeLists.txt file with your widget files.  
+
*Update the <i>Libs/q***Widgets/Plugins/CMakeLists.txt</i> file with your widget files.  
** add the .h and .cxx files in the Q***WidgetsPlugin_SRCS variable
+
** add the <i>.h</i> and <i>.cxx</i> files in the <code>q***WidgetsPlugin_SRCS</code> variable
** add the .h file in the QCTKWidgetsPlugin_MOC_SRCS variable
+
** add the <i>.h</i> file in the <code>q***WidgetsPlugin_MOC_SRCS</code> variable
** if any, add the extension files as well. i.e. qCTKCollapsibleWidgetContainerExtension.cxx
+
** if any, add the extension files as well. i.e. <i>qCTKCollapsibleWidgetContainerExtension.cxx</i>
*Add your widget in the q***WidgetsPlugins::customWidgets() method in the Libs/Q***Widgets/Plugins/q***WidgetsPlugins.h file
+
*Add your widget in the <code>q***WidgetsPlugins::customWidgets()</code> method in the <i>Libs/q***Widgets/Plugins/q***WidgetsPlugins.h</i> file
  
 
'''Coding style:'''
 
'''Coding style:'''
For a better code visibility, make sure you respect the alphabetical order in the CMakeLists.txt files when you add your files in the CMake variables.
+
For a better code visibility, make sure you respect the alphabetical order in the <i>CMakeLists.txt</i> files when you add your files in the CMake variables.

Revision as of 19:59, 31 October 2009

Home < Slicer3:Developers:Projects:QtSlicer < Tutorials < WidgetWriting

Create a custom widget in Slicer

Intro

Usually a custom widget is a specialization of another widget or a group of widgets working together. If you simply want a collection of widgets in a special configuration it can be easily done in QtDesigner and probably doesn't require to be a custom widget. Custom widgets are usually created when you need to add new functionality to existing widgets or groups of widgets.

In the following we will assume you are familiar with Qt.
Here are some useful links:

Before starting

There are 2 directories where custom widgets can be. You first have to decide in what directory your custom widget should go:

  • Slicer3/Libs/qCTKWidgets: Qt only widget
  • Slicer3/Libs/qMRMLWidgets: MRML-aware widgets

A good practice is to split (if possible) your custom widget in 2 widgets, a QT only widget, and a MRML-aware widget. The MRML widget inherits from the Qt only widget.
It is important to keep the widgets basic. If you think someone else can use your custom widget differently, or if someone would need less features that the custom widget currently have, it is probably a good idea to split the widget in a main widget and a more specialized widget.

Coding style

The name of the custom widgets must follow the pattern: q[CTK|MRML][customName][baseQtWidget], where baseQtWidget is the name of the qt widget your custom widget inherits from (i.e. ComboBox, Slider, Dialog, Widget...), and customName is a descriptive name.

Note

  • When you create your widget, make sure you highly use the [Qt property system], it allows a great customization of your widget in the Qt Designer.
  • As the process to create a custom widget is similar for qCTKWidgets and qMRMLWidgets, we will use in the following the notation q***Widgets to describe either qCTKWidgets or qMRMLWidgets.

Step by step

  • Create your widget files (.h and .cxx) in the Lib/q***Widgets directory.
    • If you use an .ui file, add it in the Libs/Q***Widgets/Resources/UI directory
    • If you use icon files, add them in the Libs/Q***Widgets/Resources/Icons directory and update the Libs/q***Widgets/Resources/q***Widgets.qrc file
  • Update the Libs/q***Widgets/CMakeLists.txt file with your widget files.
    • add the .h and .cxx files in the q***Widgets_SRCS variable
    • add the .h file in the q***Widgets_MOC_SRCS variable
    • if any, add the .ui file in the q***Widgets_UI_SRCS variable
  • compile

Congratulations, you just added a custom widget in Slicer. The widget can now be used anywhere in Slicer.
However the widget doesn't show up in QDesigner, let's create the custom widget plugin for QDesigner.

Load the widget from the designer

For a presentation of creating custom widgets for Qt Designer, see http://doc.trolltech.com/designer-creating-custom-widgets.html

Step by step

  • Copy paste this template in the Libs/q***Widgets/Plugins directory.
qCTKWidget qMRMLWidget
#ifndef __qCTKCustomWidgetPlugin_h
#define __qCTKCustomWidgetPlugin_h

#include "qCTKWidgetsBasePlugin.h"
#include "qCTKWidgetsPluginWin32Header.h"

class QCTK_WIDGETS_PLUGIN_EXPORT qCTKCustomWidgetPlugin : public QObject,
                                                          public qCTKWidgetsBasePlugin
{
  Q_OBJECT

public:
  qCTKCustomWidgetPlugin(QObject *_parent = 0);
  
  QWidget *createWidget(QWidget *_parent);
  QString domXml() const;
  QString includeFile() const;
  bool isContainer() const;
  QString name() const;
  
};

#endif

Name the file qCTK[name of your widget]Plugin.h

#ifndef __qMRMLCustomWidgetPlugin_h
#define __qMRMLCustomWidgetPlugin_h

#include "qMRMLWidgetsBasePlugin.h"
#include "qMRMLWidgetsPluginWin32Header.h"

class QMRML_WIDGETS_PLUGIN_EXPORT qMRMLCustomWidgetPlugin : public QObject,
                                public qMRMLWidgetsBasePlugin
{
  Q_OBJECT

public:
  qMRMLCustomWidgetPlugin(QObject *_parent = 0);
  
  QWidget *createWidget(QWidget *_parent);
  QString domXml() const;
  QString includeFile() const;
  bool isContainer() const;
  QString name() const;
  
};

#endif

Name the file qMRML[name of your widget]Plugin.h

  • Replace CustomWidget by the name of your widget
  • Copy paste this template in the Libs/q***Widgets/Plugins directory.
qCTKWidgets qMRMLWidgets
#include "qCTKCustomWidgetPlugin.h"
#include "qCTKCustomWidget.h"

qCTKCustomWidgetPlugin::qCTKCustomWidgetPlugin(QObject *_parent)
        : QObject(_parent)
{

}

QWidget *qCTKCustomWidgetPlugin::createWidget(QWidget *_parent)
{
  qCTKCustomWidget* _widget = new qCTKCustomWidget(_parent);
  return _widget;
}

QString qCTKCustomWidgetPlugin::domXml() const
{
  return "<widget class=\"qCTKCustomWidget\" \
          name=\"CTKCustomWidget\">\n"
          "</widget>\n";
}

QString qCTKCustomWidgetPlugin::includeFile() const
{
  return "qCTKCustomWidget.h";
}

bool qCTKCustomWidgetPlugin::isContainer() const
{
  return false;
}

QString qCTKCustomWidgetPlugin::name() const
{
  return "qCTKCustomWidget";
}

Name the file qCTK[name of your widget]Plugin.cxx

#include "qMRMLCustomWidgetPlugin.h"
#include "qMRMLCustomWidget.h"

qMRMLCustomWidgetPlugin::qMRMLCustomWidgetPlugin(QObject *_parent)
        : QObject(_parent)
{

}

QWidget *qMRMLCustomWidgetPlugin::createWidget(QWidget *_parent)
{
  qMRMLCustomWidget* _widget = new qMRMLCustomWidget(_parent);
  return _widget;
}

QString qMRMLCustomWidgetPlugin::domXml() const
{
  return "<widget class=\"qMRMLCustomWidget\" \
          name=\"MRMLCustomWidget\">\n"
          "</widget>\n";
}

QString qMRMLCustomWidgetPlugin::includeFile() const
{
  return "qMRMLCustomWidget.h";
}

bool qMRMLCustomWidgetPlugin::isContainer() const
{
  return false;
}

QString qMRMLCustomWidgetPlugin::name() const
{
  return "qMRMLCustomWidget";
}

Name the file qMRML[name of your widget]Plugin.cxx

  • Replace CustomWidget by the name of your widget
  • If the widget is a container, return true in the method isContainer(). See qCTKCollapsibleWidgetPlugin.cxx for more information.
  • You can customize how the widget look in the designer by modifying the domxml() method.
  • Update the Libs/q***Widgets/Plugins/CMakeLists.txt file with your widget files.
    • add the .h and .cxx files in the q***WidgetsPlugin_SRCS variable
    • add the .h file in the q***WidgetsPlugin_MOC_SRCS variable
    • if any, add the extension files as well. i.e. qCTKCollapsibleWidgetContainerExtension.cxx
  • Add your widget in the q***WidgetsPlugins::customWidgets() method in the Libs/q***Widgets/Plugins/q***WidgetsPlugins.h file

Coding style: For a better code visibility, make sure you respect the alphabetical order in the CMakeLists.txt files when you add your files in the CMake variables.