Dear all,
In a new Extension I recently made SlicerOrbitSurgerySim (installable in Extension Manager in Slicer 5.10), when I run a function called onInitialRegistrationPushButton from the plateRegistration module, the node selectors (qMRMLSubjectHierarchyComboBox) were set up to None, which then set all the connected parameterNode objects to None. However, I only encountered the issue in the new Slicer 5.10 and previous Slicer 5.9.1, not in Slicer 5.8.1.
In the script, each qMRMLSubjectHierarchyComboBox is connected to a parameter node, which is also connect to a function for connecting to a parameter node and also enable/disable visualization.
For example, a fiducial selector below is connected to a function: self.ui.orbitFiducialSelector.connect(“currentItemChanged(vtkIdType)”, self.onSelectOrbitLmNode)
In the onSelectOrbitLmNode function, the object is then connect to a parameter node:
def onSelectOrbitLmNode(self):
shNode = slicer.vtkMRMLSubjectHierarchyNode.GetSubjectHierarchyNode(slicer.mrmlScene)
try:
orbitLmId = self.ui.orbitFiducialSelector.currentItem()
self._parameterNode.orbitLm = shNode.GetItemDataNode(orbitLmId)
self._parameterNode.orbitLm.GetDisplayNode().SetVisibility(True)
except:
pass
I found that, in onInitialRegistrationPushButton function, after creating a folder, and pass a parameterNode object into the folder (lines 704-711) like:
plateModelItem = self.folderNode.GetItemByDataNode(self._parameterNode.rigidRegisteredPlateModel)
self.folderNode.SetItemParent(plateModelItem, self.plateRegistrationFolder)
All qMRMLSubjectHierarchyComboBox would be set to None, and so did the parameterNode.
The current solution I found is to the UI signal by adding the below four lines before line 710 (i.e., before adding any item to the folder) in plateRegistration.py:
blockers = [
qt.QSignalBlocker(self.ui.inputOrbitModelSelector),
qt.QSignalBlocker(self.ui.orbitFiducialSelector),
qt.QSignalBlocker(self.ui.plateModelSelector),
qt.QSignalBlocker(self.ui.plateFiducialSelector),
]
It would be a bit difficult to directly debug the original module script. But it could be replicated by install SlicerOrbitSurgerySim from Extension Manager, restart Slicer, go to Sample Data, download the plateRegistration Sample Data and populate the combo boxes and click “initial registration”.
I tried to create a demo module for replicate this issue, hopefully it recaptured the issue properly. Here is the testing module.
To replicate, download the zipped module, install the demo extension in Slicer 5.10.0 using Extension Wizard.
After that, use the Markups module to create a point list, and click ‘Subject hierarchy folder test’ button at the very bottom (ignore everything else). You should see that the qt combo box at the first row changed to ‘None’.
This shouldn’t be the case. This module simply select a markup node in the first row’s qtMRMLSubjectHierarchyComboBox inputSelector and pass it to a parameter node as below:
# Connections
self.ui.inputSelector.connect("currentItemChanged(vtkIdType)", self.onInputSelector)
self.ui.inputSelector.setMRMLScene(slicer.mrmlScene)
self.ui.inputSelector.setNodeTypes(['vtkMRMLMarkupsFiducialNode'])
def onInputSelector(self):
shNode = slicer.vtkMRMLSubjectHierarchyNode.GetSubjectHierarchyNode(slicer.mrmlScene)
try:
inputLmId = self.ui.inputSelector.currentItem()
self._parameterNode.inputLM = shNode.GetItemDataNode(inputLmId)
self._parameterNode.inputLM.GetDisplayNode().SetVisibility(True)
except:
pass
Afterwards, the subjectHierarchy folder test simply created a folder and pass self._parameterNode.inputLM into the folder.
def onShTestButton(self) -> None:
"""
Test for the bug: move a parameter-node-referenced node into a SubjectHierarchy folder
and see if parameter node / selectors get reset to None.
"""
print("\n=== SubjectHierarchy folder test ===")
# Make sure we have a parameter node
if not self._parameterNode:
print("No parameter node yet; initializing.")
self.initializeParameterNode()
p = self._parameterNode
# Ensure we have an input volume
inputNode = p.inputLM
if not inputNode:
inputNode = self.ui.inputSelector.currentNode()
if inputNode:
p.inputLM = inputNode
if not inputNode:
print("ERROR: No input volume selected; cannot proceed with test.")
return
# Create a SubjectHierarchy folder and move the parameter node under it
shNode = slicer.vtkMRMLSubjectHierarchyNode.GetSubjectHierarchyNode(slicer.mrmlScene)
sceneItemID = shNode.GetSceneItemID()
folderName = "ParamNodeSHTestFolder"
folderItemID = shNode.CreateFolderItem(sceneItemID, folderName)
# print(f"Created folder item: {folderItemID} with name '{folderName}'")
itemID = shNode.GetItemByDataNode(p.inputLM)
shNode.SetItemParent(itemID, folderItemID)
print(f'parameter node orbitLm check 7 {p.inputLM}')
In Slicer 5.10.0, the qtMRMLSubjectHierarchyComboBox would be turned to None.
What I found that disturbed the qtMRMLSubjectHierarchyComboBox (inputSelector) is probably due to the combox was connected to the onInputSelector function to connect it with a parameter node. If I disable the onInputSelector function at line 255 connected to the inputSelector as well as the connection at line 179, the combo box stopped switched to None anymore.
Again, in Slicer 5.8.1, there was no such issue.
Sorry, the explanation and error replication is lengthy. I could not find a shorter way to explain it. Also, interestingly, this error only appeared at the first run. If I ran the same module in the same scene again, the issue would not occur.
Thanks for looking at it!