Documentation/Nightly/Developers/Slicelets

From Slicer Wiki
Revision as of 19:05, 16 August 2014 by Lasso (talk | contribs) (Created page with '<noinclude>{{documentation/versioncheck}}</noinclude> =Slicelets= Slicer application user interface is very rich and complex, to allow free experimentation with all available t…')
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search
Home < Documentation < Nightly < Developers < Slicelets


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