Difference between revisions of "Slicer3:EventBroker"
From NAMIC Wiki
Line 66: | Line 66: | ||
EventBroker code should have the option to put out log files that are compatible with [http://www.graphviz.org graphviz] .dot file format. This can be rendered with a variety of programs, or even pasted directly in the wiki: | EventBroker code should have the option to put out log files that are compatible with [http://www.graphviz.org graphviz] .dot file format. This can be rendered with a variety of programs, or even pasted directly in the wiki: | ||
+ | === Simple Dependency === | ||
<graphviz border='frame' format='svg'> | <graphviz border='frame' format='svg'> | ||
digraph G { | digraph G { | ||
Line 72: | Line 73: | ||
</graphviz> | </graphviz> | ||
+ | === Subset of Slicer Dependencies === | ||
<graphviz border='frame' format='svg'> | <graphviz border='frame' format='svg'> | ||
− | digraph G { | + | strict digraph G { |
vtkMRMLModelDisplayNode -> vtkMRMLModelDisplayNode [ label = "ModifiedEvent" ] | vtkMRMLModelDisplayNode -> vtkMRMLModelDisplayNode [ label = "ModifiedEvent" ] | ||
; vtkMRMLScalarVolumeDisplayNode -> vtkMRMLScalarVolumeDisplayNode [ label = "ModifiedEvent" ] | ; vtkMRMLScalarVolumeDisplayNode -> vtkMRMLScalarVolumeDisplayNode [ label = "ModifiedEvent" ] |
Revision as of 14:23, 29 January 2008
Home < Slicer3:EventBrokerContents
Currently
The basic idea of the EventBroker is that currently we have a lot of this kind of code in GUIs:
node->AddObserver(vtkCommand::ModifiedEvent, callbackCommand)
Problems
The problems with this:
- node 'owns' the observer, but the callbackCommand is opaque so it doesn't know anything about what will happen when the event is invoked
- the GUI needs to explicitly remove the observer before it is destroyed
- node is not introspectable; you cannot get a list of observers on the node
- there's no easy way to know what side effects will happen for any Set call (either a priori or experimentally).
- there's no way to collapse events or disable them
Goals for Solution
So the EventBroker would be a singleton, perhaps owned by the MRML Scene that would look something like:
broker->AddObservation(node, vtkCommand::ModifiedEvent, this, callbackCommand);
The broker would do the following:
- add DeleteEvent observers to both node and this so it can remove the observer automatically if either side is destroyed
- keep an introspectable list of all observers it knows about
- have an option to keep a log of all event invocations for debugging and performance analysis
- have an option to turn off all event invocations
- have an option to queue all event invocations and invoke them later
- have methods to collapse redundant events in the queue
- perhaps have method to pass event invocations from a processing thread to the main GUI thread?
- the callbackCommand could be avoided if the vtkObject had a virtual method like this:
virtual void HandleEvent( vtkObject *caller, unsigned long event, void *clientData, void *callData );
- vtkEventBroker can have a class static GetInstance() method returning pointer to the global broker (like the way vtkSlicerApplication is done).
Additional possible extensions:
- rather than maintaining a distinct queue, the broker could queue events into the GUI event queue
- the event queue could be protected by a mutex lock so that multiple threads can access the MRML scene in parallel but only the GUI thread talks to the display
- add a timer to log the amount of time taken to process each event
References
- Java Message Service (JMS) API
- Wikipedia definition of Observer Pattern
- A C++ implementation
- Another C++ implementation
- The Qt implementation
Dependency Graphs
EventBroker code should have the option to put out log files that are compatible with graphviz .dot file format. This can be rendered with a variety of programs, or even pasted directly in the wiki:
Simple Dependency
<graphviz border='frame' format='svg'> digraph G {
vtkImageViewer -> vtkImageEllipsoidSource[ label = ModifiedEvent ]
- }
</graphviz>
Subset of Slicer Dependencies
<graphviz border='frame' format='svg'> strict digraph G {
vtkMRMLModelDisplayNode -> vtkMRMLModelDisplayNode [ label = "ModifiedEvent" ]
- vtkMRMLScalarVolumeDisplayNode -> vtkMRMLScalarVolumeDisplayNode [ label = "ModifiedEvent" ]
- vtkMRMLLabelMapVolumeDisplayNode -> vtkMRMLLabelMapVolumeDisplayNode [ label = "ModifiedEvent" ]
- vtkMRMLDiffusionWeightedVolumeDisplayNode -> vtkMRMLDiffusionWeightedVolumeDisplayNode [ label = "ModifiedEvent" ]
- vtkMRMLDiffusionTensorVolumeDisplayNode -> vtkMRMLDiffusionTensorVolumeDisplayNode [ label = "ModifiedEvent" ]
- vtkMRMLFiberBundleLineDisplayNode -> vtkMRMLFiberBundleLineDisplayNode [ label = "ModifiedEvent" ]
- vtkMRMLFiberBundleTubeDisplayNode -> vtkMRMLFiberBundleTubeDisplayNode [ label = "ModifiedEvent" ]
- vtkMRMLFiberBundleGlyphDisplayNode -> vtkMRMLFiberBundleGlyphDisplayNode [ label = "ModifiedEvent" ]
- vtkMRMLCameraNode -> vtkOpenGLCamera [ label = "ModifiedEvent" ]
- vtkMRMLUnstructuredGridDisplayNode -> vtkMRMLUnstructuredGridDisplayNode [ label = "ModifiedEvent" ]
- vtkMRMLCameraNode -> vtkOpenGLCamera [ label = "ModifiedEvent" ]
- vtkMRMLModelDisplayNode -> vtkMRMLModelDisplayNode [ label = "ModifiedEvent" ]
- vtkMRMLCameraNode -> vtkOpenGLCamera [ label = "ModifiedEvent" ]
- vtkMRMLModelNode -> vtkPolyData [ label = "ModifiedEvent" ]
- vtkMRMLModelNode -> vtkPolyData [ label = "ModifiedEvent" ]
- vtkMRMLModelDisplayNode -> vtkMRMLModelDisplayNode [ label = "ModifiedEvent" ]
- vtkMRMLModelDisplayNode -> vtkImageData [ label = "ModifiedEvent" ]
- vtkMRMLModelNode -> vtkPolyData [ label = "ModifiedEvent" ]
- vtkMRMLModelDisplayNode -> vtkMRMLModelDisplayNode [ label = "ModifiedEvent" ]
- vtkMRMLModelDisplayNode -> vtkImageData [ label = "ModifiedEvent" ]
- vtkMRMLModelNode -> vtkPolyData [ label = "ModifiedEvent" ]
- vtkMRMLModelDisplayNode -> vtkMRMLModelDisplayNode [ label = "ModifiedEvent" ]
- vtkMRMLModelDisplayNode -> vtkImageData [ label = "ModifiedEvent" ]
- }
</graphviz>