|
|
(6 intermediate revisions by 2 users not shown) |
Line 1: |
Line 1: |
− | == Currently ==
| + | <big>'''Note:''' We are migrating this content to the slicer.org domain - <font color="orange">The newer page is [https://www.slicer.org/wiki/Slicer3:EventBroker here]</font></big> |
− | 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
| |
− | | |
− | == EventBroker Solution ==
| |
− | | |
− | The EventBroker is a singleton, available as:
| |
− | | |
− | vtkEventBroker *broker = vtkEventBroker::GetInstance();
| |
− | | |
− | with the broker, you can make a call like the following:
| |
− | | |
− | broker->AddObservation(node, vtkCommand::ModifiedEvent, this, callbackCommand);
| |
− | | |
− | where ''node'' is the subject of the observation.
| |
− | | |
− | The broker does the following:
| |
− | | |
− | * adds DeleteEvent observers to both ''node'' and ''this'' so it can remove the observation automatically when either side is destroyed
| |
− | | |
− | * keeps an introspectable list of all observers it knows about
| |
− | | |
− | * has an option to keep a log of all event invocations for debugging and performance analysis
| |
− | | |
− | * has an option to turn off all event invocations
| |
− | | |
− | * has an ''asynchronous'' option to queue all event invocations and invoke them later (off by default)
| |
− | | |
− | * has option to collapse redundant events in the queue
| |
− | | |
− | The broker is also available for use from tcl. For convenience in slicer there's a global variable for the broker so you can use a code snippet like:
| |
− | | |
− | $::slicer3::broker AddObservation $node ModifiedEvent {puts "$node was modified"}
| |
− | | |
− | Future options include:
| |
− | | |
− | * add a timer to log the amount of time taken to process each event
| |
− | | |
− | See the file [http://www.na-mic.org/Slicer/Documentation/Slicer3/html/classvtkEventBroker.html Libs/MRML/vtkEventBroker.h] for more information on logging options and introspection features.
| |
− | | |
− | ==References==
| |
− | | |
− | * [http://java.sun.com/products/jms/javadoc-102a/index.html Java Message Service (JMS) API]
| |
− | * [http://en.wikipedia.org/wiki/Observer_pattern Wikipedia definition of Observer Pattern]
| |
− | * [http://xlobject.sourceforge.net/ A C++ implementation]
| |
− | * [http://sigslot.sourceforge.net/ Another C++ implementation]
| |
− | * [http://doc.trolltech.com/4.3/signalsandslots.html The Qt implementation]
| |
− | | |
− | ==Dependency Graphs==
| |
− | | |
− | 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'>
| |
− | 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> | |
− | | |
− | == Issues ==
| |
− | | |
− | * how to work with the vtkObserverManager?
| |