Documentation/Nightly/Developers/Slicelets
For the latest Slicer documentation, visit the read-the-docs. |
Slicelets
Slicer application user interface is very rich and complex, to allow free experimentation with all available tools. However, if Slicer is used for implementing a well-defined workflow, it is more efficient to develop a custom user interface, that only shows the required user interfaced, in a streamlined, simplified fashion.
Slicelets are special Slicer modules that can provide full user interface, which can be used instead of Slicer's main application user interface.
Runnning a slicelet
There are not too many differences between slicelets and regular module. In fact, any regular module can be run standalone, without the main application user interface. The --no-main-window command-line argument has to be specified to prevent showing the main application user interface and --python-code has to be provided to start the module.
For example, to show the Command line module "Add", you could use (note: on Windows replace ./Slicer by Slicer.exe):
./Slicer --no-main-window --python-code "slicer.modules.add.widgetRepresentation().show()"
.... to show a Loadable module, you could use:
./Slicer --no-main-window --python-code "slicer.modules.models.widgetRepresentation().show()"
In general, additional user interface elements need to be added if a module is used without the main application user interface, for example for loading data and saving the results. A simple example is the Label Statistics module, which can run as a regular module in Slicer but also can be started as a Slicelet. When it is started as a slicelet, it has buttons for loading input data:
./Slicer --no-main-window --python-code "slicer.modules.labelstatistics.widgetRepresentation().show()"
A slicelet implemented in python can be started from a custom location (the advantage is that the module does not have to be added to the Slicer module paths, but a disadvantage is that the module location has to be known):
./Slicer --no-main-window --python-script lib/Slicer-4.3/qt-scripted-modules/LabelStatistics.py
The line may be too complex to enter each time to start a slicelet. Either a shortcut or batch file can be created that runs the command or the command-line arguments can be hardcoded in the Slicer application settings:
Edit SlicerLauncherSettings.ini.
Before:
... [Application] path=<APPLAUNCHER_DIR>/bin/./SlicerQT-real arguments= ...
After:
... [Application] path=<APPLAUNCHER_DIR>/bin/./SlicerQT-real arguments=--no-main-window ...
Doing so, you wouldn't have to type the argument --no-main-window each time.
Similarly, you could also include the --python-code "..." arguments into the launcher settings file.
Alternatively, instead of adding the "--python-code" argument into the launcher settings, you could create a file named .slicerrc.py inside your home folder with the following content:
modules = ["add", "models", "labelstatistics"] for module in modules: getattr(slicer.modules, module).widgetRepresentation().show()
Slicelet examples
Simple example: Label Statistics module (https://github.com/Slicer/Slicer/blob/master/Modules/Scripted/LabelStatistics/LabelStatistics.py)
A more sophisticated version where these three modules are within a tab widget:
import qt import __main__ tabWidget = qt.QTabWidget() modules = ["add", "models", "labelstatistics"] for module in modules: tabWidget.addTab(getattr(slicer.modules, module).widgetRepresentation(), module) tabWidget.show() __main__.tabWidget = tabWidget # Keep track of the widget to avoid its premature destruction
Finally, to create a small UI including:
- a 3D view
- a button to load data
- a tab widget
- a module selector allowing to add any module to the tab widget
... the following could be done:
def onModuleSelected(modulename): global tabWidget tabWidget.addTab(getattr(slicer.modules, modulename.lower()).widgetRepresentation(), modulename) import qt import __main__ mainWidget = qt.QWidget() vlayout = qt.QVBoxLayout() mainWidget.setLayout(vlayout) layoutManager = slicer.qMRMLLayoutWidget() layoutManager.setMRMLScene(slicer.mrmlScene) layoutManager.setLayout(slicer.vtkMRMLLayoutNode.SlicerLayoutOneUp3DView) vlayout.addWidget(layoutManager) hlayout = qt.QHBoxLayout() vlayout.addLayout(hlayout) loadDataButton = qt.QPushButton("Load Data") hlayout.addWidget(loadDataButton) loadDataButton.connect('clicked()', slicer.util.openAddVolumeDialog) saveDataButton = qt.QPushButton("Save Data") hlayout.addWidget(saveDataButton) saveDataButton.connect('clicked()', slicer.util.openSaveDataDialog) moduleSelector = slicer.qSlicerModuleSelectorToolBar() moduleSelector.setModuleManager(slicer.app.moduleManager()) hlayout.addWidget(moduleSelector) moduleSelector.connect('moduleSelected(QString)', onModuleSelected) tabWidget = qt.QTabWidget() vlayout.addWidget(tabWidget) modules = ["add", "models", "labelstatistics"] for module in modules: onModuleSelected(module) mainWidget.show() __main__.mainWidget = mainWidget # Keep track of the widget to avoid its premature destruction
Another, more complex example: https://www.assembla.com/code/Scoliosis/subversion/nodes/52/trunk/Scoliosis/src/ScoliosisMonitoring/ScoliosisMonitoring.py