Documentation/4.5/Developers/DisplayableManagers
For the latest Slicer documentation, visit the read-the-docs. |
Contents
Displayable Managers
Displayable managers automatically observe the scene and when a matching display node is added into the scene, they create corresponding VTK actors to add them in their VTK renderer. For example, the model displayable manager creates a vtkPolyDataActor and vtkPolyDataMapper when a vtkMRMLModelDisplayNode is added into the scene.
Displayable managers are registered into a view factory (e.g. 3D view displayable manager factory) and when a view is created, the factory instantiate each displayable manager and associate them to the view.
There is 1 instance of each displayable manager per view/renderer. For example, in the conventional layout, the 2D model displayable manager (vtkMRMLModelSliceDisplayableManager
) is instantiated 3 times: once for the red slice view, once for the yellow slice view and once for the green slice view.
Theoretically the slice logics should be displayable managers ( however, it might be a huge effort for just the sake of being consistent ).
Methods
Useful methods of displayable manager to reimplement:
- OnMRMLSceneNodeAdded(vtkMRMLNode*): to observe the scene and setup observations of nodes of interest as soon as they are added into the scene
- OnMRMLNodeModified(vtkMRMLNode*): called each time a node is modified, it is here that you can update the display (typically update the VTK widgets).
Build
Displayable managers are instantiated from their class name by the displayable manager groups. An instantiator must be included in the library containing the displayable manager. To do so, add in your CMakeLists.txt:
set(displayable_manager_SRCS vtkMRMXYZDisplayableManager.cxx ) set(VTK_USE_INSTANTIATOR_NEW 1) VTK_MAKE_INSTANTIATOR3("${MODULE_NAME}Instantiator" displayable_manager_instantiator_SRCS "${displayable_manager_SRCS}" "${${KIT}_EXPORT_DIRECTIVE}" ${CMAKE_CURRENT_BINARY_DIR} "${KIT}Export.h" ) set(${KIT}_SRCS ${displayable_manager_instantiator_SRCS} ${displayable_manager_SRCS} ... )
Register
Displayable managers must be registered as early as possible (before the first view is created. Therefore, displayable managers should be registered when modules are setup.
... #include "XYZInstantiator.h" ... void qSlicerXYZModule::setup() { ... // If the displayable manager is for 3D views: vtkMRMLThreeDViewDisplayableManagerFactory::GetInstance()->RegisterDisplayableManager( "vtkMRMLXYZDisplayableManager"); // If the displayable manager is for 2D views: vtkMRMLSliceViewDisplayableManagerFactory::GetInstance()->RegisterDisplayableManager( "vtkMRMLXYZDisplayableManager"); ... }
Do not forget to include the Instantiator header file to make sure it is loaded with the module.
Displayable managers contain some limitations
- there is no control (yet?) over their creation, and once instantiated, it's not easy to control their behavior (properties can't be set externally on displayable managers).
- they are not (yet?) well designed to communicate with each others.
How a view is refreshed
It's the 3D view (ctkVTKAbstractView) that controls WHEN the vtkRenderWindow::Render is called. There are 2 ways to tell the view to re-render:
vtkRenderWindowInteractor::Render()
is called (byvtkInteractorStyle
when the mouse is moved or by some vtkWidgets that call it internally). The request is blocked andctkAbstractView::scheduleRender()
is called on the view.- or it is done by the
vtkMRMLDisplayableManager
s (e.g.vtkMRMLVolumeRenderingDisplayableManager
) by the RequestRender() calls. They call vtkMRMLDisplayableManagerGroup::RequestRender() which fires a vtkCommand::UpdateEvent. The Qt view (e.g.qMRMLThreeDView
) observes theUpdateEvent
and callsctkVTKAbstractView::scheduleRender()
.
The CTK view compacts the render requests and ensure the FPS (vtkRenderWindow::GetDesiredUpdateRate()
) is respected.
vtkInteractorStyle ---------------------------\ vtkWidget -------------------------------------> vtkRenderWindowInteractor::Render() ------------------------------\ vtkMRML???DisplayableManager::RequestRender() -> vtkMRML???DisplayableManagerGroup::RequestRender() -> UpdateEvent -> ctkVTKAbstractView::scheduleRender()