qMRMLColorTableNode causing Slicer to exit abnormally

I have been having problems using qMRMLColorTableComboBox and I can’t seem to figure it out. I’m using Slicer 4.10.1 and after creating the object and manipulating it as shown below, then upon closing the Slicer main window it will result in an exit abnormally message. Am I manipulating this in an incorrect way? Does an exit abnormally message usually indicate a specific issue with MRML widgets?

class ColorTableTest():
  def __init__(self):
    self.combobox = slicer.qMRMLColorTableComboBox()
    self.combobox.setMRMLScene(slicer.mrmlScene)

class_instance = ColorTableTest()
class_instance.combobox.setCurrentNodeID("vtkMRMLColorTableNodeGrey")
Python console user input: class ColorTableTest():
Python console user input:   def __init__(self):
Python console user input:     self.combobox = slicer.qMRMLColorTableComboBox()
Python console user input:     self.combobox.setMRMLScene(slicer.mrmlScene)
Python console user input: class_instance = ColorTableTest()
This function is deprecated. Use currentNodeID() instead
qMRMLNodeFactory::baseName failed: class name vtkMRMLColorTableNode not found
This function is deprecated. Use currentNodeID() instead
qMRMLNodeFactory::baseName failed: class name vtkMRMLColorTableNode not found
qMRMLNodeFactory::baseName failed: class name vtkMRMLColorTableNode not found
This function is deprecated. Use currentNodeID() instead
This function is deprecated. Use currentNodeID() instead
qMRMLNodeFactory::baseName failed: class name vtkMRMLColorTableNode not found
This function is deprecated. Use currentNodeID() instead
qMRMLNodeFactory::baseName failed: class name vtkMRMLColorTableNode not found
qMRMLNodeFactory::baseName failed: class name vtkMRMLColorTableNode not found
This function is deprecated. Use currentNodeID() instead
This function is deprecated. Use currentNodeID() instead
qMRMLNodeFactory::baseName failed: class name vtkMRMLColorTableNode not found
This function is deprecated. Use currentNodeID() instead
qMRMLNodeFactory::baseName failed: class name vtkMRMLColorTableNode not found
qMRMLNodeFactory::baseName failed: class name vtkMRMLColorTableNode not found
This function is deprecated. Use currentNodeID() instead
Python console user input: class_instance.combobox.setCurrentNodeID("vtkMRMLColorTableNodeGrey")
Switch to module:  ""
Switch to module:  ""
error: [C:/S4.10R/Slicer-build/bin/Release/SlicerApp-real.exe] exit abnormally - Report the problem.

It is due to trying to update a widget (triggered by removing of nodes) when the GUI of the application has been already partially destroyed. You should be able to fix this by destroying the combobox or at least set its scene to None when your module widget is destroyed.

To avoid the deprecation warnings, use class_instance.combobox.currentNodeID = "vtkMRMLColorTableNodeGrey" instead of setCurrentNodeID().

What’s the correct signal that I should be using?

Would I set it up as

self.combobox.destroyed.connect( #method that clears scene or destroys object)

or is this too late and needs some signal before it gets destroyed?
I’ve tried the above and it seems to still exit abnormally.

Set scene to None in the destructor of the module widget class.

In my test above adding the following seemed to prevent it from exiting abnormally (setting the scene to None was still causing exit abnormally with this test).

class ColorTableTest():
  def __init__(self):
    self.combobox = slicer.qMRMLColorTableComboBox()
    self.combobox.setMRMLScene(slicer.mrmlScene)
  def __del__(self):
    self.combobox.delete()

However, in my real application, I’m still struggling to prevent the exit abnormally even with defining the destructor with this code in multiple areas too. Would I need to build a Slicer debug version and connect to process to nail this down further?

I’m able to use slicer.qSlicerScalarVolumeDisplayWidget() which includes a qMRMLColorTableComboBox and doesn’t cause an exit abnormally.

I attempted to try making a qMRMLNodeComboBox into a qMRMLColorTableComboBox, but I was also struggling to get this working as well.

Colors module logic destructor removes default color nodes from the scene. This happens very late and causes all these troubles. Color module should not pollute the scene with default color nodes anyway, so changing this should make the shutdown more robust. We’ve been planning to do this, but has not found a ND the time yet. It would be a backward-incompatible change, a good fit for current master branch, where we have many of those already.

To debug this, you certainly need a debug-mode build of Slicer.

In scripted module, you could override the cleanup method of the widget.

https://github.com/Slicer/Slicer/blob/10bf184d585f7526b8083043da671b0970043a16/Base/Python/slicer/ScriptedLoadableModule.py#L99-L106

What’s the correct signal that I should be using?

You could also directly observe the signal qSlicerModuleManager::moduleAboutToBeUnloaded(QString), if module name being unloaded is YourModuleName, you would perform the cleanup and disconnect the signal.

Thanks for the ideas!

I think I have found a solution that will work for my code.

Doing slicer.app.aboutToQuit.connect(self.myCleanup) appears to handle the delete() calls for the qMRMLColorTableComboBox widgets in an early enough time to prevent the exit abnormally.