Modules:Python
From Slicer Wiki
Home < Modules:Python
Basics of building a Python GUI module for Slicer3
Python GUI modules all subclass ScriptedModuleGUI and override selected methods. Below is a full example of a gradient aniostropic diffusion module.
from SlicerScriptedModule import ScriptedModuleGUI from Slicer import slicer vtkKWScale_ScaleValueChangedEvent = 10001 vtkKWScale_ScaleValueStartChangingEvent = 10002 vtkSlicerNodeSelectorWidget_NodeSelectedEvent = 11000 vtkKWPushButton_InvokedEvent = 10000 class PythonGADScriptedModuleGUI(ScriptedModuleGUI): def __init__(self): ScriptedModuleGUI.__init__(self) self.GadNodeSelector = slicer.vtkSlicerNodeSelectorWidget() self.ConductanceScale = slicer.vtkKWScaleWithEntry() self.TimeStepScale = slicer.vtkKWScaleWithEntry() self.NumberOfIterationsScale = slicer.vtkKWScaleWithEntry() self.VolumeSelector = slicer.vtkSlicerNodeSelectorWidget() self.OutVolumeSelector = slicer.vtkSlicerNodeSelectorWidget() self.ApplyButton = slicer.vtkKWPushButton() def Destructor(self): pass def RemoveMRMLNodeObservers(self): pass def RemoveLogicObservers(self): pass def AddGUIObservers(self): self.ConductanceScaleChangingTag = self.AddObserverByNumber(self.ConductanceScale,vtkKWScale_ScaleValueStartChangingEvent) self.ConductanceScaleChangedTag = self.AddObserverByNumber(self.ConductanceScale,vtkKWScale_ScaleValueChangedEvent) self.TimeStepScaleChangingTag = self.AddObserverByNumber(self.TimeStepScale,vtkKWScale_ScaleValueStartChangingEvent) self.TimeStepScaleChangedTag = self.AddObserverByNumber(self.TimeStepScale,vtkKWScale_ScaleValueChangedEvent) self.NumberOfIterationsScaleChangingTag = self.AddObserverByNumber(self.NumberOfIterationsScale,vtkKWScale_ScaleValueStartChangingEvent) self.NumberOfIterationsScaleChangedTag = self.AddObserverByNumber(self.NumberOfIterationsScale,vtkKWScale_ScaleValueChangedEvent) self.VolumeSelectorSelectedTag = self.AddObserverByNumber(self.VolumeSelector,vtkSlicerNodeSelectorWidget_NodeSelectedEvent) self.OutVolumeSelectorSelectedTag = self.AddObserverByNumber(self.OutVolumeSelector,vtkSlicerNodeSelectorWidget_NodeSelectedEvent) self.GadNodeSelectorSelectedTag = self.AddObserverByNumber(self.GadNodeSelector,vtkSlicerNodeSelectorWidget_NodeSelectedEvent) self.ApplyButtonTag = self.AddObserverByNumber(self.ApplyButton,vtkKWPushButton_InvokedEvent) def RemoveGUIObservers(self): self.RemoveObserver(self.ConductanceScaleChangingTag) self.RemoveObserver(self.ConductanceScaleChangedTag) self.RemoveObserver(self.TimeStepScaleChangingTag) self.RemoveObserver(self.TimeStepScaleChangedTag) self.RemoveObserver(self.NumberOfIterationsScaleChangingTag) self.RemoveObserver(self.NumberOfIterationsScaleChangedTag) self.RemoveObserver(self.VolumeSelectorSelectedTag) self.RemoveObserver(self.OutVolumeSelectorSelectedTag) self.RemoveObserver(self.GadNodeSelectorSelectedTag) self.RemoveObserver(self.ApplyButtonTag) def ProcessGUIEvents(self,caller,event): if caller == self.ConductanceScale and event == vtkKWScale_ScaleValueChangedEvent: self.UpdateMRML() elif caller == self.TimeStepScale and event == vtkKWScale_ScaleValueChangedEvent: self.UpdateMRML() elif caller == self.NumberOfIterationsScale and event == vtkKWScale_ScaleValueChangedEvent: self.UpdateMRML() elif caller == self.VolumeSelector and event == vtkSlicerNodeSelectorWidget_NodeSelectedEvent and self.VolumeSelector.GetSelected(): self.UpdateMRML() elif caller == self.OutVolumeSelector and event == vtkSlicerNodeSelectorWidget_NodeSelectedEvent and self.OutVolumeSelector.GetSelected(): self.UpdateMRML() elif caller == self.GadNodeSelector and event == vtkSlicerNodeSelectorWidget_NodeSelectedEvent and self.GadNodeSelector.GetSelected(): node = self.GadNodeSelector.GetSelected() self.GetLogic().SetAndObserveScriptedModuleNode(node) self.SetAndObserveScriptedModuleNode(node) self.UpdateGUI() elif caller == self.ApplyButton and event == vtkKWPushButton_InvokedEvent: self.UpdateMRML() self.Apply() def Apply(self): if not self.GetScriptedModuleNode(): slicer.Application.ErrorMessage("No input ScriptedModuleNode found") return scriptedModuleNode = self.GetScriptedModuleNode() inVolume = scriptedModuleNode.GetParameter('InputVolumeRef') if not inVolume: slicer.Application.ErrorMessage("No input volume found") return outVolume = scriptedModuleNode.GetParameter('OutputVolumeRef') if not outVolume: slicer.Application.ErrorMessage("No output volume found") return outVolume.CopyOrientation(inVolume) outVolume.SetAndObserveTransformNodeID(inVolume.GetTransformNodeID()) gradientAnisotropicDiffusionImageFilter = slicer.vtkITKGradientAnisotropicDiffusionImageFilter() gradientAnisotropicDiffusionImageFilter.SetInput(inVolume.GetImageData()) gradientAnisotropicDiffusionImageFilter.SetConductanceParameter(scriptedModuleNode.GetParameter('Conductance')) gradientAnisotropicDiffusionImageFilter.SetNumberOfIterations(scriptedModuleNode.GetParameter('NumberOfIterations')) gradientAnisotropicDiffusionImageFilter.SetTimeStep(scriptedModuleNode.GetParameter('TimeStep')) gradientAnisotropicDiffusionImageFilter.Update() image = slicer.vtkImageData() image.DeepCopy(gradientAnisotropicDiffusionImageFilter.GetOutput()) outVolume.SetAndObserveImageData(image) outVolume.ModifiedSinceReadOn() slicer.Application.InformationMessage("Done applying GradientAnisotropicDiffusion.") def UpdateMRML(self): node = self.GetScriptedModuleNode() if not node: self.GadNodeSelector.SetSelectedNew("vtkMRMLScriptedModuleNode") self.GadNodeSelector.ProcessNewNodeCommand("vtkMRMLScriptedModuleNode", "GADParameters") node = self.GadNodeSelector.GetSelected() self.GetLogic().SetAndObserveScriptedModuleNode(node) self.SetScriptedModuleNode(node) self.GetLogic().GetMRMLScene().SaveStateForUndo(node) node.SetParameter('Conductance',self.ConductanceScale.GetValue()) node.SetParameter('TimeStep',self.TimeStepScale.GetValue()) node.SetParameter('NumberOfIterations',self.NumberOfIterationsScale.GetValue()) if self.VolumeSelector.GetSelected(): node.SetParameter('InputVolumeRef',self.VolumeSelector.GetSelected()) if self.OutVolumeSelector.GetSelected(): node.SetParameter('OutputVolumeRef',self.OutVolumeSelector.GetSelected()) def UpdateGUI(self): node = self.GetScriptedModuleNode() if node: conductance = node.GetParameter('Conductance') if conductance: self.ConductanceScale.SetValue(conductance) numberOfIterations = node.GetParameter('NumberOfIterations') if numberOfIterations: self.NumberOfIterationsScale.SetValue(numberOfIterations) timeStep = node.GetParameter('TimeStep') if timeStep: self.TimeStepScale.SetValue(timeStep) def ProcessMRMLEvents(self,caller,event): if self.GetScriptedModuleNode() == caller: self.UpdateGUI() def BuildGUI(self): self.GetUIPanel().AddPage("GradientAnisotropicDiffusionFilter","GradientAnisotropicDiffusionFilter","") pageWidget = self.GetUIPanel().GetPageWidget("GradientAnisotropicDiffusionFilter") helpText = "Flex, dude!" aboutText = "This work is supported by NA-MIC, NAC, BIRN, NCIGT, and the Slicer Community. See http://www.slicer.org for details." self.BuildHelpAndAboutFrame(pageWidget,helpText,aboutText) moduleFrame = slicer.vtkSlicerModuleCollapsibleFrame() moduleFrame.SetParent(self.GetUIPanel().GetPageWidget("GradientAnisotropicDiffusionFilter")) moduleFrame.Create() moduleFrame.SetLabelText("Gradient Anisotropic Diffusion Filter") moduleFrame.ExpandFrame() widgetName = moduleFrame.GetWidgetName() pageWidgetName = self.GetUIPanel().GetPageWidget("GradientAnisotropicDiffusionFilter").GetWidgetName() slicer.TkCall("pack %s -side top -anchor nw -fill x -padx 2 -pady 2 -in %s" % (widgetName,pageWidgetName)) self.GadNodeSelector.SetNodeClass("vtkMRMLScriptedModuleNode", "ScriptedModuleName", self.GetLogic().GetModuleName(), "GADParameters") self.GadNodeSelector.NewNodeEnabledOn() self.GadNodeSelector.NoneEnabledOn() self.GadNodeSelector.ShowHiddenOn() self.GadNodeSelector.SetParent(moduleFrame.GetFrame()) self.GadNodeSelector.Create() self.GadNodeSelector.SetMRMLScene(self.GetLogic().GetMRMLScene()) self.GadNodeSelector.UpdateMenu() self.GadNodeSelector.SetBorderWidth(2) self.GadNodeSelector.SetLabelText("GAD Parameters") self.GadNodeSelector.SetBalloonHelpString("select a GAD node from the current mrml scene.") slicer.TkCall("pack %s -side top -anchor e -padx 20 -pady 4" % self.GadNodeSelector.GetWidgetName()) self.ConductanceScale.SetParent(moduleFrame.GetFrame()) self.ConductanceScale.SetLabelText("Conductance") self.ConductanceScale.Create() w = self.ConductanceScale.GetScale().GetWidth() self.ConductanceScale.SetRange(0,10) self.ConductanceScale.SetResolution(0.1) self.ConductanceScale.SetValue(1.0) slicer.TkCall("pack %s -side top -anchor e -padx 20 -pady 4" % self.ConductanceScale.GetWidgetName()) self.TimeStepScale.SetParent(moduleFrame.GetFrame()) self.TimeStepScale.SetLabelText("Time Step") self.TimeStepScale.Create() self.TimeStepScale.GetScale().SetWidth(w) self.TimeStepScale.SetRange(0.0,1.0) self.TimeStepScale.SetValue(0.1) self.TimeStepScale.SetResolution(0.01) slicer.TkCall("pack %s -side top -anchor e -padx 20 -pady 4" % self.TimeStepScale.GetWidgetName()) self.NumberOfIterationsScale.SetParent(moduleFrame.GetFrame()) self.NumberOfIterationsScale.SetLabelText("Iterations") self.NumberOfIterationsScale.Create() self.NumberOfIterationsScale.GetScale().SetWidth(w) self.NumberOfIterationsScale.SetValue(1) slicer.TkCall("pack %s -side top -anchor e -padx 20 -pady 4" % self.NumberOfIterationsScale.GetWidgetName()) self.VolumeSelector.SetNodeClass("vtkMRMLScalarVolumeNode","","","") self.VolumeSelector.SetParent(moduleFrame.GetFrame()) self.VolumeSelector.Create() self.VolumeSelector.SetMRMLScene(self.GetLogic().GetMRMLScene()) self.VolumeSelector.UpdateMenu() self.VolumeSelector.SetBorderWidth(2) self.VolumeSelector.SetLabelText("Input Volume: ") self.VolumeSelector.SetBalloonHelpString("select an input volume from the current mrml scene.") slicer.TkCall("pack %s -side top -anchor e -padx 20 -pady 4" % self.VolumeSelector.GetWidgetName()) self.OutVolumeSelector.SetNodeClass("vtkMRMLScalarVolumeNode","","","GADVolumeOut") self.OutVolumeSelector.SetNewNodeEnabled(1) self.OutVolumeSelector.SetParent(moduleFrame.GetFrame()) self.OutVolumeSelector.Create() self.OutVolumeSelector.SetMRMLScene(self.GetLogic().GetMRMLScene()) self.OutVolumeSelector.UpdateMenu() self.OutVolumeSelector.SetBorderWidth(2) self.OutVolumeSelector.SetLabelText("Output Volume: ") self.OutVolumeSelector.SetBalloonHelpString("select an output volume from the current mrml scene.") slicer.TkCall("pack %s -side top -anchor e -padx 20 -pady 4" % self.OutVolumeSelector.GetWidgetName()) self.ApplyButton.SetParent(moduleFrame.GetFrame()) self.ApplyButton.Create() self.ApplyButton.SetText("Apply") self.ApplyButton.SetWidth(8) slicer.TkCall("pack %s -side top -anchor e -padx 20 -pady 10" % self.ApplyButton.GetWidgetName()) def TearDownGUI(self): self.GadNodeSelector.SetParent(None) self.GadNodeSelector = None self.ConductanceScale.SetParent(None) self.ConductanceScale = None self.TimeStepScale.SetParent(None) self.TimeStepScale = None self.NumberOfIterationsScale.SetParent(None) self.NumberOfIterationsScale = None self.VolumeSelector.SetParent(None) self.VolumeSelector = None self.OutVolumeSelector.SetParent(None) self.OutVolumeSelector = None self.ApplyButton.SetParent(None) self.ApplyButton = None if self.GetUIPanel().GetUserInterfaceManager(): pageWidget = self.GetUIPanel().GetPageWidget("GradientAnisotropicDiffusionFilter") self.GetUIPanel().RemovePage("GradientAnisotropicDiffusionFilter")