|
Slicer 4.2
Slicer is a multi-platform, free and open source software package for visualization and medical image computing
|
00001 import slicer 00002 from __main__ import qt 00003 from __main__ import ctk 00004 from __main__ import vtk 00005 from __main__ import getNodes 00006 import EditUtil 00007 00008 ######################################################### 00009 # 00010 # 00011 comment = """ 00012 In this file: 00013 00014 Helpers - small widget-like helper classes 00015 EditOptions - EffectOptions superclass 00016 00017 Each effect interface is created when the corresponding 00018 editor effect is active on the slice views. The main 00019 (only) responsibility of these GUIs is to set parameters 00020 on the mrml node that influence the behavior of the 00021 editor effects. 00022 00023 """ 00024 # 00025 ######################################################### 00026 00027 ######################################################### 00028 # Helpers 00029 ######################################################### 00030 00031 class HelpButton(object): 00032 """ 00033 Puts a button on the interface that pops up a message 00034 dialog for help when pressed 00035 """ 00036 def __init__(self, parent, helpString = ""): 00037 self.helpString = helpString 00038 self.message = qt.QMessageBox() 00039 self.message.setWindowTitle("Editor Help") 00040 self.button = qt.QPushButton("?", parent) 00041 self.button.setMaximumWidth(15) 00042 self.button.setToolTip("Bring up a help window") 00043 parent.layout().addWidget(self.button) 00044 self.button.connect('clicked()', self.showHelp) 00045 00046 def showHelp(self): 00047 self.message.setText(self.helpString) 00048 self.message.open() 00049 00050 ######################################################### 00051 # Options 00052 ######################################################### 00053 class EditOptions(object): 00054 """ This EditOptions is a parent class for all the GUI options 00055 for editor effects. These are small custom interfaces 00056 that it in the toolOptionsFrame of the Editor interface. 00057 TODO: no support yet for scope options 00058 """ 00059 00060 def __init__(self, parent=None): 00061 self.parent = parent 00062 self.updatingGUI = False 00063 self.observerTags = [] 00064 self.widgets = [] 00065 self.parameterNode = None 00066 self.parameterNodeTag = None 00067 self.editUtil = EditUtil.EditUtil() 00068 self.tools = [] 00069 00070 # connections is a list of widget/signal/slot tripples 00071 # for the options gui that can be connected/disconnected 00072 # as needed to prevent triggering mrml updates while 00073 # updating the state of the gui 00074 # - each level of the inheritance tree can add entries 00075 # to this list for use by the connectWidgets 00076 # and disconnectWidgets methods 00077 self.connections = [] 00078 self.connectionsConnected = False 00079 00080 # 1) find the parameter node in the scene and observe it 00081 # 2) set the defaults (will only set them if they are not 00082 # already set) 00083 self.updateParameterNode(self.parameterNode, vtk.vtkCommand.ModifiedEvent) 00084 self.setMRMLDefaults() 00085 00086 # TODO: change this to look for specfic events (added, removed...) 00087 # but this requires being able to access events by number from wrapped code 00088 tag = slicer.mrmlScene.AddObserver(vtk.vtkCommand.ModifiedEvent, self.updateParameterNode) 00089 self.observerTags.append( (slicer.mrmlScene, tag) ) 00090 00091 def __del__(self): 00092 self.destroy() 00093 if self.parameterNode: 00094 self.parameterNode.RemoveObserver(self.parameterNodeTag) 00095 for tagpair in self.observerTags: 00096 tagpair[0].RemoveObserver(tagpair[1]) 00097 00098 def connectWidgets(self): 00099 if self.connectionsConnected: return 00100 for widget,signal,slot in self.connections: 00101 success = widget.connect(signal,slot) 00102 if not success: 00103 print("Could not connect {signal} to {slot} for {widget}".format( 00104 signal = signal, slot = slot, widget = widget)) 00105 self.connectionsConnected = True 00106 00107 def disconnectWidgets(self): 00108 if not self.connectionsConnected: return 00109 for widget,signal,slot in self.connections: 00110 success = widget.disconnect(signal,slot) 00111 if not success: 00112 print("Could not disconnect {signal} to {slot} for {widget}".format( 00113 signal = signal, slot = slot, widget = widget)) 00114 self.connectionsConnected = False 00115 00116 def create(self): 00117 if not self.parent: 00118 self.parent = slicer.qMRMLWidget() 00119 self.parent.setLayout(qt.QVBoxLayout()) 00120 self.parent.setMRMLScene(slicer.mrmlScene) 00121 self.parent.show() 00122 self.frame = qt.QFrame(self.parent) 00123 self.frame.setLayout(qt.QVBoxLayout()) 00124 self.parent.layout().addWidget(self.frame) 00125 self.widgets.append(self.frame) 00126 00127 def destroy(self): 00128 for w in self.widgets: 00129 self.parent.layout().removeWidget(w) 00130 w.deleteLater() 00131 w.setParent(None) 00132 self.widgets = [] 00133 00134 # 00135 # update the GUI for the given label 00136 # - to be overriden by the subclass 00137 # 00138 def updateMRMLFromGUI(self): 00139 pass 00140 00141 # 00142 # update the GUI from MRML 00143 # - to be overriden by the subclass 00144 # 00145 def updateGUIFromMRML(self,caller,event): 00146 pass 00147 00148 # 00149 # update the GUI from MRML 00150 # - to be overriden by the subclass 00151 # 00152 def updateGUI(self): 00153 self.updateGUIFromMRML(self.parameterNode, vtk.vtkCommand.ModifiedEvent) 00154 00155 # 00156 # set the default option values 00157 # - to be overriden by the subclass 00158 # 00159 def setMRMLDefaults(self): 00160 pass 00161 00162 def getBackgroundScalarRange(self): 00163 success = False 00164 lo = -1 00165 hi = -1 00166 backgroundVolume = self.editUtil.getBackgroundVolume() 00167 if backgroundVolume: 00168 backgroundImage = backgroundVolume.GetImageData() 00169 if backgroundImage: 00170 lo, hi = backgroundImage.GetScalarRange() 00171 success = True 00172 return success, lo, hi 00173 00174 def setRangeWidgetToBackgroundRange(self, rangeWidget): 00175 """Set the range widget based on current backgroun 00176 volume - note that hi+1 is used since the range widget 00177 will round floating numbers to 2 significant digits""" 00178 if not rangeWidget: 00179 return 00180 success, lo, hi = self.getBackgroundScalarRange() 00181 if success: 00182 rangeWidget.minimum, rangeWidget.maximum = lo, hi+1 00183 00184 def statusText(self,text): 00185 slicer.util.showStatusMessage(text) 00186 00187 def debug(self,text): 00188 import inspect 00189 print('*'*80) 00190 print(text) 00191 print(self) 00192 stack = inspect.stack() 00193 for frame in stack: 00194 print(frame)
1.7.4