qMRMLSubjectHierarchyComboBox usage

How to get notified in Python when currentItemChanged fires? I tried this:

# myCB1 is qMRMLNodeComboBox
# myCB2 is qMRMLSubjectHierarchyComboBox
myCB1.connect('currentNodeChanged(vtkMRMLNode*)', self.updateMRMLFromGUI)
myCB2.connect('currentItemChanged(int)', self.updateMRMLFromGUI)

def updateMRMLFromGUI(self, **unused):
  # gets called for myCB1, but not for myCB2

How to make only volumes selectable, and not studies or patients? For qMRMLNodeComboBox this .ui fragment only shows volumes:

   <widget class="qMRMLNodeComboBox" name="myCB1">
    <property name="nodeTypes">
     <stringlist>
      <string>vtkMRMLScalarVolumeNode</string>
     </stringlist>
    </property>

Is there an equivalent or similar thing for qMRMLSubjectHierarchyComboBox either as .ui fragment or Python snippet?

First question:
self.usPatientItemCombobox.connect('currentItemChanged(vtkIdType)', self.onUSPatientSelectionChanged)

Second question:
If you only want to be able to select volumes, then simply use qMRMLNodeComboBox. If you want to see the hierarchy as well, but only have the volumes in the hierarchy show up, then you can easily add a filter similar to the attribute filter in the combobox class

I have tried myCB2.connect('currentItemChanged(vtkIdType)', self.updateMRMLFromGUI) first, and since that didn’t work I also tried int to which vtkIdType resolves. Does Python have a 64-bit int?

I have seen the method setAttributeFilter, but no example of its usage. Can you provide a few example calls to this method, even if it doesn’t accomplish what I want?

I agree, it would be great to have some examples in SH Python tests and a few words about this in the class documentation would be useful, too.

Not sure what you mean by “a few words”, but there is as much in the documentation as there can be for an extremely simple feature like this I think:


and

Would you add something else?

I’ll add a test about it to the SH generic test. Apparently it started failing last night, so I need to check up on it anyway.

Example in new test section:
https://github.com/Slicer/Slicer/commit/e66e3b08e35384526528e6ae678e9ec9f079f286#diff-8cdc75584ed1fbe2b0be1e655a2f22a1R352

@dzenanz Where do you think we should link or reference existing documentation and code samples to streamline your developer experience ?

@cpinter Thanks, that test is very useful as an example.

@jcfr I expected the examples to be either on the labs page or in the script repository. I will add Csaba’s test as an example in the script repository.

Still, currentItemChanged does not trigger for me. Parts of actual code:

self._get('projectionImage').connect('currentItemChanged(vtkIdType)', self.shChanged) # setting updateMRMLFromGUI directly as slot doesn't work either
self._get('outputImage').connect('currentNodeChanged(vtkMRMLNode*)', self.updateMRMLFromGUI) # gets triggered properly

def shChanged(self, shID):
    self.updateMRMLFromGUI(shID)
    print "Triggered: "+str(shID)
  
def updateMRMLFromGUI(self, **unused):
    # handle the change

Link to newly added docs: https://www.slicer.org/wiki/Documentation/Nightly/ScriptRepository#Filter_nodes_in_TreeView_or_ComboBox

Thanks! I have two comments:

  1. I think the Qt designer plugins are an irrelevant detail for this example
  2. The entities that you show and in this case filter in SH are not nodes, but they are items. It’s important, because for many of the items there is no corresponding MRML node. This may actually confuse people who want to filter in node attribute, when in reality the filter applies on SH item attributes.

I quickly fixed it myself.

Thanks @cpinter for docs fix.

Can you provide declaration for onUSPatientSelectionChanged, corresponding to this code fragment?

self.usPatientItemCombobox.connect('currentItemChanged(vtkIdType)', self.onUSPatientSelectionChanged)

Of course, the example is from the SegmentRegistration extension:

Filtering does not work, and copy-pasting from SegmentRegistration didn’t help for event triggering:

def __init__(self, parent=None):
  slicer.qMRMLWidget.__init__(self, parent)
  slicer.util.VTKObservationMixin.__init__(self)
  ...
  self._get('projectionImage').connect('currentItemChanged(vtkIdType)', self.shChanged)
  # self._get('projectionImage').setAttributeFilter('DICOM.Modality','NM') #combobox empty if enabled
  self._get('outputImage').connect('currentNodeChanged(vtkMRMLNode*)', self.updateMRMLFromGUI)
  
  # copy-pasted code, combobox is displayed and shows the hierarchy properly
  self.usPatientItemCombobox = slicer.qMRMLSubjectHierarchyComboBox()
  self.usPatientItemCombobox.name = "usPatientItemCombobox"
  self.usPatientItemCombobox.setMRMLScene( slicer.mrmlScene )
  self._get('ioNodes').layout().addRow('US patient', self.usPatientItemCombobox)
  self.usPatientItemCombobox.connect('currentItemChanged(vtkIdType)', self.onUSPatientSelectionChanged)
  ...
  
def onUSPatientSelectionChanged(self, usPatientShItemID):
  print "usPatientShItemID: "+str(usPatientShItemID)

I will try to create a minimum working example to diagnose what is going on.

When you say something “doesn’t work”, please tell us how it doesn’t work. See https://www.slicer.org/wiki/Documentation/Nightly/Report_a_problem#Error_report_contents

With this line present, the projectionImage qMRMLSubjectHierarchyComboBox doesn’t display any nodes
36
even if there are nodes which have NM modality:
58

Indeed, the screenshot shows that the item does have that attribute. What happens if you set the same filter on the SH tree view? You can get it like this:
dmw=slicer.modules.data.widgetRepresentation()
sht=slicer.util.findChildren(dmw,className=‘qMRMLSubjectHierarchyTreeView’)[0]

If I create a combobox like this (I had a CT in the scene), it works with the latest version:
c=slicer.qMRMLSubjectHierarchyComboBox()
c.setMRMLScene(slicer.mrmlScene)
c.show()
c.setAttributeFilter(‘DICOM.Modality’,‘CT’)

Basic question but are you sure you set the scene to the combobox?

Another thing to check: Try if it works if you set the attribute before you create the widget (the order should not matter but maybe there is a bug and the tree is not re-filtered when an attribute is changed).

1 Like

@lassoan Even if data is loaded (and hence attributes are set) before my widget is created/accessed, I did not notice any change.

I created the minimum working example in this commit. The problematic lines are 16-19.

@cpinter Have you tried my MWE?