Skip to content

Instantly share code, notes, and snippets.

@mikebind
Last active February 3, 2022 23:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mikebind/a3a4ee96076ab23d0e0339a47d02adfb to your computer and use it in GitHub Desktop.
Save mikebind/a3a4ee96076ab23d0e0339a47d02adfb to your computer and use it in GitHub Desktop.
import logging
import os
import unittest
import vtk, qt, ctk, slicer
import SegmentStatistics
from slicer.ScriptedLoadableModule import *
from slicer.util import TESTING_DATA_URL
from slicer.util import VTKObservationMixin
class TestDebug2(ScriptedLoadableModule):
"""Uses ScriptedLoadableModule base class, available at:
https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py
"""
def __init__(self, parent):
ScriptedLoadableModule.__init__(self, parent)
self.parent.title = "TestCheckbox" # TODO make this more human readable by adding spaces
self.parent.categories = ["Examples"]
self.parent.dependencies = []
self.parent.contributors = ["John Doe (AnyWare Corp.)"] # replace with "Firstname Lastname (Organization)"
self.parent.helpText = """
The Help text for this scripted module.
"""
self.parent.helpText += self.getDefaultModuleDocumentationLink()
self.parent.acknowledgementText = """
The acknowledgementText
"""
#
# TestDebug2Widget
#
class TestDebug2Widget(ScriptedLoadableModuleWidget, VTKObservationMixin):
"""Uses ScriptedLoadableModuleWidget base class, available at:
https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py
"""
def __init__(self, parent=None):
"""
Called when the user opens the module the first time and the widget is initialized.
"""
ScriptedLoadableModuleWidget.__init__(self, parent)
VTKObservationMixin.__init__(self) # needed for parameter node observation
self.logic = None
self._parameterNode = None
self._updatingGUIFromParameterNode = False
def setup(self):
ScriptedLoadableModuleWidget.setup(self)
# Instantiate and connect widgets ...
#
# Parameters Area
#
parametersCollapsibleButton = ctk.ctkCollapsibleButton()
parametersCollapsibleButton.text = "ROI"
self.layout.addWidget(parametersCollapsibleButton)
parametersFormLayout = qt.QFormLayout(parametersCollapsibleButton)
self.logic = TestDebug2Logic()
#
# input volume selector
#
self.inputSelector = slicer.qMRMLNodeComboBox()
self.inputSelector.nodeTypes = ["vtkMRMLScalarVolumeNode"]
self.inputSelector.selectNodeUponCreation = True
self.inputSelector.addEnabled = False
self.inputSelector.removeEnabled = False
self.inputSelector.noneEnabled = False
self.inputSelector.showHidden = False
self.inputSelector.showChildNodeTypes = False
self.inputSelector.setMRMLScene(slicer.mrmlScene)
self.inputSelector.setToolTip( "Pick the input to the algorithm." )
parametersFormLayout.addRow("Input Volume: ", self.inputSelector)
#
# ROI checkbox
#
self.ROICheckBox = ctk.ctkCheckBox()
self.ROICheckBox.enabled = True
self.ROICheckBox.checked = False
parametersFormLayout.addRow("ROI:", self.ROICheckBox)
# self.ROICheckBox.setMRMLVolumeNode(volNode)
self.addObserver(slicer.mrmlScene, slicer.mrmlScene.StartCloseEvent, self.onSceneStartClose)
self.addObserver(slicer.mrmlScene, slicer.mrmlScene.EndCloseEvent, self.onSceneEndClose)
# connections
self.inputSelector.connect("currentNodeChanged(vtkMRMLNode*)", self.onInputVolumeSelectorChange)
self.ROICheckBox.connect('clicked(bool)', self.onCheckBox)
self.initializeParameterNode()
# Add vertical spacer
self.layout.addStretch(1)
def onInputVolumeSelectorChange(self):
"""
Called when the input volume selector selection changes
"""
roiCheckedFlag = self.ROICheckBox.checked # true if ROI checkbox is checked
volRenLogic = slicer.modules.volumerendering.logic()
# Get new volume node
newVolNode = self.inputSelector.currentNode()
if newVolNode:
volRenDispNode = volRenLogic.GetFirstVolumeRenderingDisplayNode(newVolNode)
newROINode = volRenDispNode.GetROINode()
if newROINode:
newROIIsVisible = bool(newROINode.GetDisplayNode().GetVisibility())
# Set checkbox based on current ROI visibility
self.ROICheckBox.checked = newROIIsVisible
# update parameter node
self.updateParameterNodeFromGUI()
def onCheckBox(self):
"""
Called when the checkbox is toggled
"""
VolumeNode = self._parameterNode.GetNodeReference('InputVolume')
if VolumeNode:
self.logic.updateROIOnVolume(VolumeNode, self.ROICheckBox.checked)
self.updateParameterNodeFromGUI()
def cleanup(self):
"""
Called when the application closes and the module widget is destroyed.
"""
self.removeObservers()
def enter(self):
"""
Called each time the user opens this module.
"""
# Make sure parameter node exists and observed
self.initializeParameterNode()
def exit(self):
"""
Called each time the user opens a different module.
"""
# Do not react to parameter node changes (GUI wlil be updated when the user enters into the module)
self.removeObserver(self._parameterNode, vtk.vtkCommand.ModifiedEvent, self.updateGUIFromParameterNode)
def onSceneStartClose(self, caller, event):
"""
Called just before the scene is closed.
"""
# Parameter node will be reset, do not use it anymore
self.setParameterNode(None)
def onSceneEndClose(self, caller, event):
"""
Called just after the scene is closed.
"""
# If this module is shown while the scene is closed then recreate a new parameter node immediately
if self.parent.isEntered:
self.initializeParameterNode()
def initializeParameterNode(self):
"""
Ensure parameter node exists and observed.
"""
# Parameter node stores all user choices in parameter values, node selections, etc.
# so that when the scene is saved and reloaded, these settings are restored.
self.setParameterNode(self.logic.getParameterNode())
# Select default input nodes if nothing is selected yet to save a few clicks for the user
if not self._parameterNode.GetNodeReference("InputVolume"):
firstVolumeNode = slicer.mrmlScene.GetFirstNodeByClass("vtkMRMLScalarVolumeNode")
if firstVolumeNode:
self._parameterNode.SetNodeReferenceID("InputVolume", firstVolumeNode.GetID())
def setParameterNode(self, inputParameterNode):
"""
Set and observe parameter node.
Observation is needed because when the parameter node is changed then the GUI must be updated immediately.
"""
# Unobserve previously selected parameter node and add an observer to the newly selected.
# Changes of parameter node are observed so that whenever parameters are changed by a script or any other module
# those are reflected immediately in the GUI.
if self._parameterNode is not None:
self.removeObserver(self._parameterNode, vtk.vtkCommand.ModifiedEvent, self.updateGUIFromParameterNode)
self._parameterNode = inputParameterNode
if self._parameterNode is not None:
self.addObserver(self._parameterNode, vtk.vtkCommand.ModifiedEvent, self.updateGUIFromParameterNode)
# Initial GUI update
self.updateGUIFromParameterNode()
def updateGUIFromParameterNode(self, caller=None, event=None):
"""
This method is called whenever parameter node is changed.
The module GUI is updated to show the current state of the parameter node.
"""
if self._parameterNode is None or self._updatingGUIFromParameterNode:
return
# Make sure GUI changes do not call updateParameterNodeFromGUI (it could cause infinite loop)
self._updatingGUIFromParameterNode = True
# Update node selectors and sliders
self.inputSelector.setCurrentNode(self._parameterNode.GetNodeReference("InputVolume"))
self.ROICheckBox.checked = (self._parameterNode.GetParameter("ROI") == "true")
# All the GUI updates are done
self._updatingGUIFromParameterNode = False
def updateParameterNodeFromGUI(self, caller=None, event=None):
"""
This method is called when the user makes any change in the GUI.
The changes are saved into the parameter node (so that they are restored when the scene is saved and loaded).
"""
if self._parameterNode is None or self._updatingGUIFromParameterNode:
return
wasModified = self._parameterNode.StartModify() # Modify all properties in a single batch
self._parameterNode.SetNodeReferenceID("InputVolume", self.inputSelector.currentNodeID)
self._parameterNode.SetParameter("ROI", "true" if self.ROICheckBox.checked else "false")
self._parameterNode.EndModify(wasModified)
#
# TestDebug2Logic
#
class TestDebug2Logic(ScriptedLoadableModuleLogic):
"""This class should implement all the actual
computation done by your module. The interface
should be such that other python code can import
this class and make use of the functionality without
requiring an instance of the Widget.
Uses ScriptedLoadableModuleLogic base class, available at:
https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py
"""
def __init__(self):
"""
Called when the logic class is instantiated. Can be used for initializing member variables.
"""
ScriptedLoadableModuleLogic.__init__(self)
def updateROIOnVolume(self, VolumeNode, ROIchecked=False):
""" Controls visibility of the volume rendering ROI for the currently selected
input volume
"""
volRenDispNode = slicer.modules.volumerendering.logic().GetFirstVolumeRenderingDisplayNode(VolumeNode)
roiNode = volRenDispNode.GetROINode()
if ROIchecked:
roiNode.GetDisplayNode().SetVisibility(1)
else:
roiNode.GetDisplayNode().SetVisibility(0)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment