1import types 2import tkinter 3import Pmw 4import collections 5 6class RadioSelect(Pmw.MegaWidget): 7 # A collection of several buttons. In single mode, only one 8 # button may be selected. In multiple mode, any number of buttons 9 # may be selected. 10 11 def __init__(self, parent = None, **kw): 12 13 # Define the megawidget options. 14 INITOPT = Pmw.INITOPT 15 optiondefs = ( 16 ('buttontype', 'button', INITOPT), 17 ('command', None, None), 18 ('labelmargin', 0, INITOPT), 19 ('labelpos', None, INITOPT), 20 ('orient', 'horizontal', INITOPT), 21 ('padx', 5, INITOPT), 22 ('pady', 5, INITOPT), 23 ('selectmode', 'single', INITOPT), 24 ) 25 self.defineoptions(kw, optiondefs, dynamicGroups = ('Button',)) 26 27 # Initialise the base class (after defining the options). 28 Pmw.MegaWidget.__init__(self, parent) 29 30 # Create the components. 31 interior = self.interior() 32 if self['labelpos'] is None: 33 self._radioSelectFrame = self._hull 34 else: 35 self._radioSelectFrame = self.createcomponent('frame', 36 (), None, 37 tkinter.Frame, (interior,)) 38 self._radioSelectFrame.grid(column=2, row=2, sticky='nsew') 39 interior.grid_columnconfigure(2, weight=1) 40 interior.grid_rowconfigure(2, weight=1) 41 42 self.createlabel(interior) 43 44 # Initialise instance variables. 45 self._buttonList = [] 46 if self['selectmode'] == 'single': 47 self._singleSelect = 1 48 elif self['selectmode'] == 'multiple': 49 self._singleSelect = 0 50 else: 51 raise ValueError('bad selectmode option "' + \ 52 self['selectmode'] + '": should be single or multiple') 53 54 if self['buttontype'] == 'button': 55 self.buttonClass = tkinter.Button 56 elif self['buttontype'] == 'radiobutton': 57 self._singleSelect = 1 58 self.var = tkinter.StringVar() 59 self.buttonClass = tkinter.Radiobutton 60 elif self['buttontype'] == 'checkbutton': 61 self._singleSelect = 0 62 self.buttonClass = tkinter.Checkbutton 63 else: 64 raise ValueError('bad buttontype option "' + \ 65 self['buttontype'] + \ 66 '": should be button, radiobutton or checkbutton') 67 68 if self._singleSelect: 69 self.selection = None 70 else: 71 self.selection = [] 72 73 if self['orient'] not in ('horizontal', 'vertical'): 74 raise ValueError('bad orient option ' + repr(self['orient']) + \ 75 ': must be either \'horizontal\' or \'vertical\'') 76 77 # Check keywords and initialise options. 78 self.initialiseoptions() 79 80 def getcurselection(self): 81 if self._singleSelect: 82 return self.selection 83 else: 84 return tuple(self.selection) 85 86 def getvalue(self): 87 return self.getcurselection() 88 89 def setvalue(self, textOrList): 90 if self._singleSelect: 91 self.__setSingleValue(textOrList) 92 else: 93 # Multiple selections 94 oldselection = self.selection 95 self.selection = textOrList 96 for button in self._buttonList: 97 if button in oldselection: 98 if button not in self.selection: 99 # button is currently selected but should not be 100 widget = self.component(button) 101 if self['buttontype'] == 'checkbutton': 102 widget.deselect() 103 else: # Button 104 widget.configure(relief='raised') 105 else: 106 if button in self.selection: 107 # button is not currently selected but should be 108 widget = self.component(button) 109 if self['buttontype'] == 'checkbutton': 110 widget.select() 111 else: # Button 112 widget.configure(relief='sunken') 113 114 def numbuttons(self): 115 return len(self._buttonList) 116 117 def index(self, index): 118 # Return the integer index of the button with the given index. 119 120 listLength = len(self._buttonList) 121 if type(index) == int: 122 if index < listLength: 123 return index 124 else: 125 raise ValueError('index "%s" is out of range' % index) 126 elif index is Pmw.END: 127 if listLength > 0: 128 return listLength - 1 129 else: 130 raise ValueError('RadioSelect has no buttons') 131 else: 132 for count in range(listLength): 133 name = self._buttonList[count] 134 if index == name: 135 return count 136 validValues = 'a name, a number or Pmw.END' 137 raise ValueError('bad index "%s": must be %s' % (index, validValues)) 138 139 def button(self, buttonIndex): 140 name = self._buttonList[self.index(buttonIndex)] 141 return self.component(name) 142 143 def add(self, componentName, **kw): 144 if componentName in self._buttonList: 145 raise ValueError('button "%s" already exists' % componentName) 146 147 kw['command'] = \ 148 lambda self=self, name=componentName: self.invoke(name) 149 if 'text' not in kw: 150 kw['text'] = componentName 151 152 if self['buttontype'] == 'radiobutton': 153 if 'anchor' not in kw: 154 kw['anchor'] = 'w' 155 if 'variable' not in kw: 156 kw['variable'] = self.var 157 if 'value' not in kw: 158 kw['value'] = kw['text'] 159 elif self['buttontype'] == 'checkbutton': 160 if 'anchor' not in kw: 161 kw['anchor'] = 'w' 162 163 button = self.createcomponent(*(componentName, 164 (), 'Button', 165 self.buttonClass, (self._radioSelectFrame,)), **kw) 166 167 if self['orient'] == 'horizontal': 168 self._radioSelectFrame.grid_rowconfigure(0, weight=1) 169 col = len(self._buttonList) 170 button.grid(column=col, row=0, padx = self['padx'], 171 pady = self['pady'], sticky='nsew') 172 self._radioSelectFrame.grid_columnconfigure(col, weight=1) 173 else: 174 self._radioSelectFrame.grid_columnconfigure(0, weight=1) 175 row = len(self._buttonList) 176 button.grid(column=0, row=row, padx = self['padx'], 177 pady = self['pady'], sticky='ew') 178 self._radioSelectFrame.grid_rowconfigure(row, weight=1) 179 180 self._buttonList.append(componentName) 181 return button 182 183 def deleteall(self): 184 for name in self._buttonList: 185 self.destroycomponent(name) 186 self._buttonList = [] 187 if self._singleSelect: 188 self.selection = None 189 else: 190 self.selection = [] 191 192 def __setSingleValue(self, value): 193 self.selection = value 194 if self['buttontype'] == 'radiobutton': 195 widget = self.component(value) 196 widget.select() 197 else: # Button 198 for button in self._buttonList: 199 widget = self.component(button) 200 if button == value: 201 widget.configure(relief='sunken') 202 else: 203 widget.configure(relief='raised') 204 205 def invoke(self, index): 206 index = self.index(index) 207 name = self._buttonList[index] 208 209 if self._singleSelect: 210 self.__setSingleValue(name) 211 command = self['command'] 212 if isinstance(command, collections.Callable): 213 return command(name) 214 else: 215 # Multiple selections 216 widget = self.component(name) 217 if name in self.selection: 218 if self['buttontype'] == 'checkbutton': 219 widget.deselect() 220 else: 221 widget.configure(relief='raised') 222 self.selection.remove(name) 223 state = 0 224 else: 225 if self['buttontype'] == 'checkbutton': 226 widget.select() 227 else: 228 widget.configure(relief='sunken') 229 self.selection.append(name) 230 state = 1 231 232 command = self['command'] 233 if isinstance(command, collections.Callable): 234 return command(name, state) 235