https://www.slicer.org/w/api.php?action=feedcontributions&user=Essert&feedformat=atomSlicer Wiki - User contributions [en]2024-03-28T16:36:54ZUser contributionsMediaWiki 1.33.0https://www.slicer.org/w/index.php?title=User:Essert&diff=58052User:Essert2018-01-15T09:19:27Z<p>Essert: </p>
<hr />
<div>Caroline ESSERT I'm an associate professor in Computer Science, PhD, from the ICUBE lab of the University of Strasbourg.<br />
I am collaborating with Sonia PUJOL on 3D Slicer development, for a needle trajectory planning project.</div>Esserthttps://www.slicer.org/w/index.php?title=Documentation/Nightly/Developers/IO&diff=58049Documentation/Nightly/Developers/IO2018-01-15T09:18:15Z<p>Essert: /* How to save files programmatically */</p>
<hr />
<div><noinclude>{{documentation/versioncheck}}</noinclude><br />
=Read=<br />
[[Image:IOOverview.png|600px|center]]<br />
== Main classes ==<br />
* <code>vtkSlicer<i>XYZ</i>Node</code> is a [http://viewvc.slicer.org/viewvc.cgi/Slicer4/trunk/Libs/MRML/Core/vtkMRMLStorableNode.h?view=markup storable node] that represents the data from file (e.g. [[http://viewvc.slicer.org/viewvc.cgi/Slicer4/trunk/Libs/MRML/Core/vtkMRMLModelNode.h?view=markup vtkMRMLModelNode])<br />
* <code>vtkSlicer<i>XYZ</i>StorageNode</code> is the file reader. It populates the storable node using the method <code>vtkMRML<i>XYZ</i>StorageNode::ReadData(vtkMRMLStorableNode*,bool)</code>.<br />
* <code>vtkSlicer<i>XYZ</i>sLogic</code> is the MRML logic of the <code>XYZ</code> module. It exposes a convenient method <code>AddXYZ(const char* fileName, const char* nodeName=0);</code> that creates a MRML <i>XYZ</i> node (<code>vtkMRML<i>XYZ</i>Node</code>)and its associated storage node (<code>vtkMRML<i>XYZ</i>StorageNode</code>), add them into the scene, and call <code>vtkMRML<i>XYZ</i>StorageNode::ReadData(vtkMRMLStorableNode*,bool);</code> on the storage node to load the file. If the loading fails, it removes the previously created nodes from the scene.<br />
* <code>qSlicer<i>XYZ</i>sIO</code> is a plugin that is registered by modules into the <code>qSlicerCoreIOManager</code>. It is the interface between Qt and MRML logics. It internally calls <code>vtkSlicer<i>XYZ</i>sLogic::Add<i>XYZ</i></code>().<br />
* <code>qSlicer<i>XYZ</i>sIOOptionsWidget</code> is a widget that sets loading options that gets passed to the logic.<br />
* <code>qSlicerCoreIOManager</code> is the central class where any IO operation must go through. qSlicerIOs can be registered using <code>qSlicerCoreIOManager::registerIO(qSlicerIO*)</code> and nodes can be loaded using <code>qSlicerCoreIOManager::loadNodes(...)</code>. It exposes a set of convenient methods such as "what reader must be used for what file".<br />
* <code>qSlicerDataDialog</code> is the dialog that allows the user to select the files to load.<br />
<br />
==How to add support for reading a new file format ?==<br />
# Write method <code>vtkMRMLXYZStorageNode::ReadDataInternal(vtkMRMLStorableNode*, bool temporary);</code><br />
# Write method <code>vtkMRMLXYZsLogic::AddXYZ(const char* fileName, const char nodeName =0);</code><br />
# Write class <code>qSlicerXYZsIO</code><br />
# Optional: Write class <code>qSlicerXYZsIOOptionsWidget</code> if you want the user to optionally specify loading options.<br />
# In <code>qSlicerXYZsModule::setup()</code>, instantiate and register <code>qSlicerXYZsIO</code> to <code>qSlicerCoreIOManager</code><br />
# Add file format to [Documentation/{{documentation/version}}/SlicerApplication/SupportedDataFormat|SupportedDataFormat] wiki page<br />
<br />
== ModifiedSinceRead ==<br />
In order to inform the user what data has been changed since it was last read, a ModifiedSinceRead mechanism is in place to track when was the file last read and when was the data last modified. If a modification happened , the storable node <code>vtkMRMLStorableNode::GetModifiedSinceRead()</code> must return true. If the data in the node is the same as in the file, then <code>vtkMRMLStorableNode::GetModifiedSinceRead()</code> must return false.<br />
<br />
<code>vtkMRMLStorageNode</code> keeps track of when a file was last read or written (<code>vtkTimeStamp* vtkMRMLStorageNode::StoredTime</code>). <code>vtkMRMLStorableNode</code> keeps track of when the data was last modified (<code>vtkTimeStamp vtkMRMLStorableNode::StorableModifiedTime</code>). Anytime a <code>vtkMRMLStorableNode</code> property that is saved in file is modified, the <code>StorableModifiedTime</code> time stamp must be modified.<br />
<br />
At exit time (<code>qSlicerMainWindow::closeEvent()</code>), <code>vtkMRMLStorableNode::GetModifiedSinceRead()</code> is called to check if the data in the node is the same as in the file or if it has been modified after the file was last read or written. It internally checks <code>vtkTimeStamp* vtkMRMLStorageNode::StoredTime</code> and <code>vtkTimeStamp vtkMRMLStorableNode::StorableModifiedTime</code>. If the data is more recent, then a message dialog is shown to the user telling him that some data is different from file; leaving without saving will lose the changes.<br />
<br />
== Example ==<br />
* Models <br />
** [http://viewvc.slicer.org/viewvc.cgi/Slicer4/trunk/Libs/MRML/Core/vtkMRMLModelNode.h?view=markup Libs/MRML/Core/vtkMRMLModelNode]<br />
** [http://viewvc.slicer.org/viewvc.cgi/Slicer4/trunk/Libs/MRML/Core/vtkMRMLModelStorageNode.h?view=markup Libs/MRML/Core/vtkMRMLModelStorageNode]<br />
** [http://viewvc.slicer.org/viewvc.cgi/Slicer4/trunk/Modules/Loadable/Models/Logic/vtkSlicerModelsLogic.h?view=markup Modules/Loadable/Models/Logic/vtkSlicerModelsLogic]<br />
** [http://viewvc.slicer.org/viewvc.cgi/Slicer4/trunk/Modules/Loadable/Models/qSlicerModelsIO.h?view=markup Modules/Loadable/Models/qSlicerModelsIO]<br />
** [http://viewvc.slicer.org/viewvc.cgi/Slicer4/trunk/Modules/Loadable/Models/qSlicerModelsModule.h?view=markup Modules/Loadable/Models/qSlicerModelsModule]<br />
<br />
== How to load files programmatically ==<br />
{|width = "100%"<br />
! style="border-bottom: 1px solid darkgrey;font-size: 75%;"|C++<br />
! style="border-bottom: 1px solid darkgrey;font-size: 75%;"|Python<br />
|-<br />
| valign="top" |<br />
[http://slicer.org/doc/html/classqSlicerCoreIOManager.html qSlicerCoreIOManager]* coreIOManager = qSlicerCoreApplication::application()->coreIOManager();<br />
qSlicerIO::IOProperties fileParameters;<br />
fileParameters["fileName"] = "/path/of/file.ext";<br />
vtkMRMLNode* volumeNode = coreIOManager->[http://slicer.org/doc/html/classqSlicerCoreIOManager.html#a36a78dba553b52f395f997fe11aaff23 loadNodesAndGetFirst]("VolumeFile", fileParameters);<br />
Works also with "ModelFile", "TransformFile", "SceneFile"...<br />
| valign="top" |<br />
>>> volumeNode = slicer.util.loadVolume('/path/of/file.ext')<br />
It works also with loadModel, loadTransform, loadScene...<br />
|}<br />
Note that [[#IO_Dialogs|IO dialogs]] should be used as often as possible.<br />
<br />
=Write=<br />
The mechanism is similar to '''Read'''. <code>vtkMRMLXYZStorageNode::WriteDataInternal(...)</code> and <code>qSlicerXYZWriter</code> must implemented.<br />
<br />
== How to save files programmatically ==<br />
{|width = "100%"<br />
! style="border-bottom: 1px solid darkgrey;font-size: 75%;"|C++<br />
! style="border-bottom: 1px solid darkgrey;font-size: 75%;"|Python<br />
|-<br />
| valign="top" |<br />
[http://slicer.org/doc/html/classqSlicerCoreIOManager.html qSlicerCoreIOManager]* coreIOManager = qSlicerCoreApplication::application()->coreIOManager();<br />
qSlicerIO::IOProperties fileParameters;<br />
fileParameters["nodeID"] = volumeNode->GetID();<br />
fileParameters["fileName"] = "/path/of/file.ext";<br />
coreIOManager->[http://slicer.org/doc/html/classqSlicerCoreIOManager.html#a1cd29140ded984afdd0f667064d38845 saveNodes]("VolumeFile", fileParameters);<br />
Works also with "ModelFile", "TransformFile", "SceneFile"...<br />
| valign="top" |<br />
>>> slicer.util.saveNode(volumeNode, '/path/of/file.ext')<br />
|}<br />
Note that [[#IO_Dialogs|IO dialogs]] should be used as often as possible.<br />
<br />
=IO Dialogs=<br />
* <code>[http://slicer.org/doc/html/classqSlicerFileDialog.html qSlicerFileDialog]</code> is the base class to override a custom dialog.<br />
* <code>[http://slicer.org/doc/html/classqSlicerStandardFileDialog.html qSlicerStandardFileDialog]</code> is a multi-purpose file dialog.<br />
* <code>[http://slicer.org/doc/html/classqSlicerDataDialog.html qSlicerDataDialog.h]</code> is the default dialog to load files.<br />
* <code>[http://slicer.org/doc/html/classqSlicerSaveDataDialog.html qSlicerSaveDataDialog]</code> is the default dialog to save files.<br />
<br />
By default, all the IOs must be done through <code>qSlicerDataDialog</code> for reading files and <code>qSlicerSaveDataDialog</code> for writing files. However, due to historical reasons, it is possible to have custom dialogs for each node types.<br />
<br />
It can be useful to create your own IO dialog to add custom behavior to the Slicer drag&drop default behavior.<br />
== How to register a dialog ? ==<br />
{|width = "100%"<br />
! style="border-bottom: 1px solid darkgrey;font-size: 75%;"|C++<br />
! style="border-bottom: 1px solid darkgrey;font-size: 75%;"|Python<br />
|-<br />
| valign="top" |<br />
Register dialogs in qSlicerXYZModule::[http://slicer.org/doc/html/classqSlicerAbstractCoreModule.html#a9ad37e756338e7226f157b4eb54b9bcd setup()]:<br />
[http://slicer.org/doc/html/classqSlicerIOManager.html qSlicerIOManager]* ioManager = qSlicerApplication::application()->ioManager();<br />
ioManager->[http://slicer.org/doc/html/classqSlicerIOManager.html#ae47e9cf27f230335b865bce84a56e156 registerDialog](new qSlicerXYZDialog(this));<br />
ioManager->[http://slicer.org/doc/html/classqSlicerIOManager.html#ae47e9cf27f230335b865bce84a56e156 registerDialog](new qSlicerSaveXYZDialog(this));<br />
| valign="top" |<br />
Declare an XYZFileDialog in your XYZ.py module file. It will be automatically registered. For example:<br />
class XYZFileDialog:<br />
def __init__(self, parent):<br />
self.parent = parent<br />
parent.fileType = 'XYZFile'<br />
parent.description = 'XYZ'<br />
parent.action = slicer.qSlicerFileDialog.Read<br />
def isMimeDataAccepted(self):<br />
accept = self.parent.mimeData().hasFormat("text/uri-list")<br />
self.parent.acceptMimeData(accept)<br />
def dropEvent(self):<br />
self.parent.dropEvent().accept()<br />
def execDialog(self):<br />
print 'exec' <br />
|}<br />
<br />
== How to open a registered a dialog ? ==<br />
{|width = "100%"<br />
! style="border-bottom: 1px solid darkgrey;font-size: 75%;"|C++<br />
! style="border-bottom: 1px solid darkgrey;font-size: 75%;"|Python<br />
|-<br />
| valign="top" |<br />
[http://slicer.org/doc/html/classqSlicerIOManager.html qSlicerIOManager]* ioManager = qSlicerApplication::application()->ioManager();<br />
ioManager->openDialog("VolumeFile", qSlicerFileDialog::Read, qSlicerIO::IOProperties());<br />
| valign="top" |<br />
io = slicer.app.ioManager()<br />
params = {}<br />
io.openDialog("VolumeFile", slicer.qSlicerFileDialog.Read, params)<br />
And the special case for standard data file types:<br />
slicer.util.openAddVolumeDialog()<br />
|}<br />
<br />
== How to order the list of drag&drop dialogs ?==<br />
By controlling the order of module initialization. This is done by adding module dependencies. Make your module dependent of of the "Data" would make it initialize after the Data module that registers the "Any Data" dialogs:<br />
{|width = "100%"<br />
! style="border-bottom: 1px solid darkgrey;font-size: 75%;"|C++<br />
! style="border-bottom: 1px solid darkgrey;font-size: 75%;"|Python<br />
|-<br />
| valign="top" |<br />
QStringList qSlicerXYZModule::dependencies() const<br />
{<br />
QStringList moduleDependencies;<br />
moduleDependencies << "Data";<br />
return moduleDependencies;<br />
}<br />
| valign="top" |<br />
def __init__(self, parent):<br />
...<br />
parent.dependencies = ["Data"] class XYZFileDialog:<br />
...<br />
|}</div>Esserthttps://www.slicer.org/w/index.php?title=Documentation/Nightly/Developers/IO&diff=58046Documentation/Nightly/Developers/IO2018-01-15T09:17:58Z<p>Essert: /* How to load files programmatically */</p>
<hr />
<div><noinclude>{{documentation/versioncheck}}</noinclude><br />
=Read=<br />
[[Image:IOOverview.png|600px|center]]<br />
== Main classes ==<br />
* <code>vtkSlicer<i>XYZ</i>Node</code> is a [http://viewvc.slicer.org/viewvc.cgi/Slicer4/trunk/Libs/MRML/Core/vtkMRMLStorableNode.h?view=markup storable node] that represents the data from file (e.g. [[http://viewvc.slicer.org/viewvc.cgi/Slicer4/trunk/Libs/MRML/Core/vtkMRMLModelNode.h?view=markup vtkMRMLModelNode])<br />
* <code>vtkSlicer<i>XYZ</i>StorageNode</code> is the file reader. It populates the storable node using the method <code>vtkMRML<i>XYZ</i>StorageNode::ReadData(vtkMRMLStorableNode*,bool)</code>.<br />
* <code>vtkSlicer<i>XYZ</i>sLogic</code> is the MRML logic of the <code>XYZ</code> module. It exposes a convenient method <code>AddXYZ(const char* fileName, const char* nodeName=0);</code> that creates a MRML <i>XYZ</i> node (<code>vtkMRML<i>XYZ</i>Node</code>)and its associated storage node (<code>vtkMRML<i>XYZ</i>StorageNode</code>), add them into the scene, and call <code>vtkMRML<i>XYZ</i>StorageNode::ReadData(vtkMRMLStorableNode*,bool);</code> on the storage node to load the file. If the loading fails, it removes the previously created nodes from the scene.<br />
* <code>qSlicer<i>XYZ</i>sIO</code> is a plugin that is registered by modules into the <code>qSlicerCoreIOManager</code>. It is the interface between Qt and MRML logics. It internally calls <code>vtkSlicer<i>XYZ</i>sLogic::Add<i>XYZ</i></code>().<br />
* <code>qSlicer<i>XYZ</i>sIOOptionsWidget</code> is a widget that sets loading options that gets passed to the logic.<br />
* <code>qSlicerCoreIOManager</code> is the central class where any IO operation must go through. qSlicerIOs can be registered using <code>qSlicerCoreIOManager::registerIO(qSlicerIO*)</code> and nodes can be loaded using <code>qSlicerCoreIOManager::loadNodes(...)</code>. It exposes a set of convenient methods such as "what reader must be used for what file".<br />
* <code>qSlicerDataDialog</code> is the dialog that allows the user to select the files to load.<br />
<br />
==How to add support for reading a new file format ?==<br />
# Write method <code>vtkMRMLXYZStorageNode::ReadDataInternal(vtkMRMLStorableNode*, bool temporary);</code><br />
# Write method <code>vtkMRMLXYZsLogic::AddXYZ(const char* fileName, const char nodeName =0);</code><br />
# Write class <code>qSlicerXYZsIO</code><br />
# Optional: Write class <code>qSlicerXYZsIOOptionsWidget</code> if you want the user to optionally specify loading options.<br />
# In <code>qSlicerXYZsModule::setup()</code>, instantiate and register <code>qSlicerXYZsIO</code> to <code>qSlicerCoreIOManager</code><br />
# Add file format to [Documentation/{{documentation/version}}/SlicerApplication/SupportedDataFormat|SupportedDataFormat] wiki page<br />
<br />
== ModifiedSinceRead ==<br />
In order to inform the user what data has been changed since it was last read, a ModifiedSinceRead mechanism is in place to track when was the file last read and when was the data last modified. If a modification happened , the storable node <code>vtkMRMLStorableNode::GetModifiedSinceRead()</code> must return true. If the data in the node is the same as in the file, then <code>vtkMRMLStorableNode::GetModifiedSinceRead()</code> must return false.<br />
<br />
<code>vtkMRMLStorageNode</code> keeps track of when a file was last read or written (<code>vtkTimeStamp* vtkMRMLStorageNode::StoredTime</code>). <code>vtkMRMLStorableNode</code> keeps track of when the data was last modified (<code>vtkTimeStamp vtkMRMLStorableNode::StorableModifiedTime</code>). Anytime a <code>vtkMRMLStorableNode</code> property that is saved in file is modified, the <code>StorableModifiedTime</code> time stamp must be modified.<br />
<br />
At exit time (<code>qSlicerMainWindow::closeEvent()</code>), <code>vtkMRMLStorableNode::GetModifiedSinceRead()</code> is called to check if the data in the node is the same as in the file or if it has been modified after the file was last read or written. It internally checks <code>vtkTimeStamp* vtkMRMLStorageNode::StoredTime</code> and <code>vtkTimeStamp vtkMRMLStorableNode::StorableModifiedTime</code>. If the data is more recent, then a message dialog is shown to the user telling him that some data is different from file; leaving without saving will lose the changes.<br />
<br />
== Example ==<br />
* Models <br />
** [http://viewvc.slicer.org/viewvc.cgi/Slicer4/trunk/Libs/MRML/Core/vtkMRMLModelNode.h?view=markup Libs/MRML/Core/vtkMRMLModelNode]<br />
** [http://viewvc.slicer.org/viewvc.cgi/Slicer4/trunk/Libs/MRML/Core/vtkMRMLModelStorageNode.h?view=markup Libs/MRML/Core/vtkMRMLModelStorageNode]<br />
** [http://viewvc.slicer.org/viewvc.cgi/Slicer4/trunk/Modules/Loadable/Models/Logic/vtkSlicerModelsLogic.h?view=markup Modules/Loadable/Models/Logic/vtkSlicerModelsLogic]<br />
** [http://viewvc.slicer.org/viewvc.cgi/Slicer4/trunk/Modules/Loadable/Models/qSlicerModelsIO.h?view=markup Modules/Loadable/Models/qSlicerModelsIO]<br />
** [http://viewvc.slicer.org/viewvc.cgi/Slicer4/trunk/Modules/Loadable/Models/qSlicerModelsModule.h?view=markup Modules/Loadable/Models/qSlicerModelsModule]<br />
<br />
== How to load files programmatically ==<br />
{|width = "100%"<br />
! style="border-bottom: 1px solid darkgrey;font-size: 75%;"|C++<br />
! style="border-bottom: 1px solid darkgrey;font-size: 75%;"|Python<br />
|-<br />
| valign="top" |<br />
[http://slicer.org/doc/html/classqSlicerCoreIOManager.html qSlicerCoreIOManager]* coreIOManager = qSlicerCoreApplication::application()->coreIOManager();<br />
qSlicerIO::IOProperties fileParameters;<br />
fileParameters["fileName"] = "/path/of/file.ext";<br />
vtkMRMLNode* volumeNode = coreIOManager->[http://slicer.org/doc/html/classqSlicerCoreIOManager.html#a36a78dba553b52f395f997fe11aaff23 loadNodesAndGetFirst]("VolumeFile", fileParameters);<br />
Works also with "ModelFile", "TransformFile", "SceneFile"...<br />
| valign="top" |<br />
>>> volumeNode = slicer.util.loadVolume('/path/of/file.ext')<br />
It works also with loadModel, loadTransform, loadScene...<br />
|}<br />
Note that [[#IO_Dialogs|IO dialogs]] should be used as often as possible.<br />
<br />
=Write=<br />
The mechanism is similar to '''Read'''. <code>vtkMRMLXYZStorageNode::WriteDataInternal(...)</code> and <code>qSlicerXYZWriter</code> must implemented.<br />
<br />
== How to save files programmatically ==<br />
{|width = "100%"<br />
! style="border-bottom: 1px solid darkgrey;font-size: 75%;"|C++<br />
! style="border-bottom: 1px solid darkgrey;font-size: 75%;"|Python<br />
|-<br />
| valign="top" |<br />
[http://slicer.org/doc/html/classqSlicerCoreIOManager.html qSlicerCoreIOManager]* coreIOManager = qSlicerCoreApplication::application()->coreIOManager();<br />
qSlicerIO::IOProperties fileParameters;<br />
fileParameters["nodeID"] = volumeNode->GetID();<br />
fileParameters["fileName"] = "/path/of/file.ext";<br />
coreIOManager->[http://slicer.org/doc/html/classqSlicerCoreIOManager.html#a1cd29140ded984afdd0f667064d38845 saveNodes]("VolumeFile", parameters);<br />
Works also with "ModelFile", "TransformFile", "SceneFile"...<br />
| valign="top" |<br />
>>> slicer.util.saveNode(volumeNode, '/path/of/file.ext')<br />
|}<br />
Note that [[#IO_Dialogs|IO dialogs]] should be used as often as possible.<br />
<br />
=IO Dialogs=<br />
* <code>[http://slicer.org/doc/html/classqSlicerFileDialog.html qSlicerFileDialog]</code> is the base class to override a custom dialog.<br />
* <code>[http://slicer.org/doc/html/classqSlicerStandardFileDialog.html qSlicerStandardFileDialog]</code> is a multi-purpose file dialog.<br />
* <code>[http://slicer.org/doc/html/classqSlicerDataDialog.html qSlicerDataDialog.h]</code> is the default dialog to load files.<br />
* <code>[http://slicer.org/doc/html/classqSlicerSaveDataDialog.html qSlicerSaveDataDialog]</code> is the default dialog to save files.<br />
<br />
By default, all the IOs must be done through <code>qSlicerDataDialog</code> for reading files and <code>qSlicerSaveDataDialog</code> for writing files. However, due to historical reasons, it is possible to have custom dialogs for each node types.<br />
<br />
It can be useful to create your own IO dialog to add custom behavior to the Slicer drag&drop default behavior.<br />
== How to register a dialog ? ==<br />
{|width = "100%"<br />
! style="border-bottom: 1px solid darkgrey;font-size: 75%;"|C++<br />
! style="border-bottom: 1px solid darkgrey;font-size: 75%;"|Python<br />
|-<br />
| valign="top" |<br />
Register dialogs in qSlicerXYZModule::[http://slicer.org/doc/html/classqSlicerAbstractCoreModule.html#a9ad37e756338e7226f157b4eb54b9bcd setup()]:<br />
[http://slicer.org/doc/html/classqSlicerIOManager.html qSlicerIOManager]* ioManager = qSlicerApplication::application()->ioManager();<br />
ioManager->[http://slicer.org/doc/html/classqSlicerIOManager.html#ae47e9cf27f230335b865bce84a56e156 registerDialog](new qSlicerXYZDialog(this));<br />
ioManager->[http://slicer.org/doc/html/classqSlicerIOManager.html#ae47e9cf27f230335b865bce84a56e156 registerDialog](new qSlicerSaveXYZDialog(this));<br />
| valign="top" |<br />
Declare an XYZFileDialog in your XYZ.py module file. It will be automatically registered. For example:<br />
class XYZFileDialog:<br />
def __init__(self, parent):<br />
self.parent = parent<br />
parent.fileType = 'XYZFile'<br />
parent.description = 'XYZ'<br />
parent.action = slicer.qSlicerFileDialog.Read<br />
def isMimeDataAccepted(self):<br />
accept = self.parent.mimeData().hasFormat("text/uri-list")<br />
self.parent.acceptMimeData(accept)<br />
def dropEvent(self):<br />
self.parent.dropEvent().accept()<br />
def execDialog(self):<br />
print 'exec' <br />
|}<br />
<br />
== How to open a registered a dialog ? ==<br />
{|width = "100%"<br />
! style="border-bottom: 1px solid darkgrey;font-size: 75%;"|C++<br />
! style="border-bottom: 1px solid darkgrey;font-size: 75%;"|Python<br />
|-<br />
| valign="top" |<br />
[http://slicer.org/doc/html/classqSlicerIOManager.html qSlicerIOManager]* ioManager = qSlicerApplication::application()->ioManager();<br />
ioManager->openDialog("VolumeFile", qSlicerFileDialog::Read, qSlicerIO::IOProperties());<br />
| valign="top" |<br />
io = slicer.app.ioManager()<br />
params = {}<br />
io.openDialog("VolumeFile", slicer.qSlicerFileDialog.Read, params)<br />
And the special case for standard data file types:<br />
slicer.util.openAddVolumeDialog()<br />
|}<br />
<br />
== How to order the list of drag&drop dialogs ?==<br />
By controlling the order of module initialization. This is done by adding module dependencies. Make your module dependent of of the "Data" would make it initialize after the Data module that registers the "Any Data" dialogs:<br />
{|width = "100%"<br />
! style="border-bottom: 1px solid darkgrey;font-size: 75%;"|C++<br />
! style="border-bottom: 1px solid darkgrey;font-size: 75%;"|Python<br />
|-<br />
| valign="top" |<br />
QStringList qSlicerXYZModule::dependencies() const<br />
{<br />
QStringList moduleDependencies;<br />
moduleDependencies << "Data";<br />
return moduleDependencies;<br />
}<br />
| valign="top" |<br />
def __init__(self, parent):<br />
...<br />
parent.dependencies = ["Data"] class XYZFileDialog:<br />
...<br />
|}</div>Essert