Documentation/4.1/Developers/Tutorials/WidgetWriting
For the latest Slicer documentation, visit the read-the-docs. |
Contents
Creating a custom widget in Slicer
Intro
A custom widget is a specialization of another widget or a group of widgets working together. Custom widgets are usually created when you need to add new functionality to existing widgets or groups of widgets. 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.
In the following we will assume you are familiar with Qt.
Here are some useful links:
- http://doc.trolltech.com/how-to-learn-qt.html
- http://doc.trolltech.com/object.html
- http://doc.trolltech.com/properties.html
Before starting
There are 2 locations where custom widgets can be. You first have to decide where your custom widget should go:
- CTK: Qt and/or VTK only
- Slicer3/Libs/qMRMLWidgets: MRML-aware widgets (Slicer3)
- Slicer/Libs/MRML/Widgets: MRML-aware widgets (Slicer4)
A good practice is to split (as possible) your custom widget in 2: a QT-only widget and a MRML-aware widget where the MRML-aware widgets inherits from the Qt-only widget. An intermediate level can be added for Qt and VTK widgets.
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 than the custom widget currently have, it is probably a good idea to split the widget in 2 widgets linked with an IS-A relationship.
Coding style
The name of the custom widgets must follow the pattern: qMRML[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. Examples:
qMRMLLinearTransformSlider
vs.qMRMLMatrixqMRMLMatrixWidget
Note
- When you create your widget, make sure you use the Qt property system, it allow the customization of the widgets in Qt Designer.
Step by step
- Create your widget files (.h and .cxx) in the Libs/MRML/Widgets directory.
- If you use a .ui file, add it in the Libs/MRML/Widgets/Resources/UI directory
- If you use icon files, add them in the Libs/MRML/Widgets/Resources/Icons directory and update the Libs/MRML/Widgets/Resources/qMRMLWidgets.qrc file accordingly
- Update the Libs/MRML/Widgets/CMakeLists.txt file with your widget files.
- add the .h and .cxx files in the
qMRMLWidgets_SRCS
variable - add the .h file in the
qMRMLWidgets_MOC_SRCS
variable - if any, add the .ui file in the
qMRMLWidgets_UI_SRCS
variable
- add the .h and .cxx files in the
- compile with your favorite compiler.
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 associated widget plugin for QDesigner.
Create a widget for the designer
For a general presentation to create 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/MRML/Widgets/Plugins directory.
#ifndef __qMRMLCustomWidgetPlugin_h #define __qMRMLCustomWidgetPlugin_h #include "qMRMLWidgetsAbstractPlugin.h" class QMRML_WIDGETS_PLUGIN_EXPORT qMRMLCustomWidgetPlugin : public QObject, public qMRMLWidgetsAbstractPlugin { Q_OBJECT public: qMRMLCustomWidgetPlugin(QObject *_parent = 0); QWidget *createWidget(QWidget *_parent); QString domXml() const; QString includeFile() const; bool isContainer() const; QString name() const; }; #endif Rename the file qMRML[name of your widget]Plugin.h |
- Replace CustomWidget with the name of your widget
- Copy-paste the following template in the Libs/MRML/Widgets/DesignerPlugins directory.
#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"; } Rename 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</code in the method
isContainer()
. - You can customize how the widget is instantiated in the designer by reimplementing the method
domxml()
. - Update Libs/MRML/Widgets/DesignerPlugins/CMakeLists.txt by adding your widget plugin files.
- add the files qMRMLCustomWidgetPlugin.h and qMRMLCustomWidgetPlugin.cxx in the variable
qMRMLWidgetsPlugin_SRCS
- add the file qMRMLCustomWidgetPlugin.h in the variable
qMRMLWidgetsPlugin_MOC_SRCS
- add the files qMRMLCustomWidgetPlugin.h and qMRMLCustomWidgetPlugin.cxx in the variable
- Finally add your widget in the method
qMRMLWidgetsPlugins::customWidgets()
of the file Libs/MRML/Widgets/DesignerPlugins/qMRMLWidgetsPlugins.h - compile
Congratulations, you just added a custom widget in a plugin that can be read by QDesigner. Read the QtDesigner tutorial to learn how you can use the widget in Qt Designer.
Coding style:
For a better code readability, make sure you respect the alphabetical order of the files in CMakeLists.txt.