import types import Tkinter import Pmw class RadioSelect(Pmw.MegaWidget): # A collection of several buttons. In single mode, only one # button may be selected. In multiple mode, any number of buttons # may be selected. def __init__(self, parent = None, **kw): # Define the megawidget options. INITOPT = Pmw.INITOPT optiondefs = ( ('buttontype', 'button', INITOPT), ('command', None, None), ('labelmargin', 0, INITOPT), ('labelpos', None, INITOPT), ('orient', 'horizontal', INITOPT), ('padx', 5, INITOPT), ('pady', 5, INITOPT), ('selectmode', 'single', INITOPT), ) self.defineoptions(kw, optiondefs, dynamicGroups = ('Button',)) # Initialise the base class (after defining the options). Pmw.MegaWidget.__init__(self, parent) # Create the components. interior = self.interior() if self['labelpos'] is None: self._radioSelectFrame = self._hull else: self._radioSelectFrame = self.createcomponent('frame', (), None, Tkinter.Frame, (interior,)) self._radioSelectFrame.grid(column=2, row=2, sticky='nsew') interior.grid_columnconfigure(2, weight=1) interior.grid_rowconfigure(2, weight=1) self.createlabel(interior) # Initialise instance variables. self._buttonList = [] if self['selectmode'] == 'single': self._singleSelect = 1 elif self['selectmode'] == 'multiple': self._singleSelect = 0 else: raise ValueError, 'bad selectmode option "' + \ self['selectmode'] + '": should be single or multiple' if self['buttontype'] == 'button': self.buttonClass = Tkinter.Button elif self['buttontype'] == 'radiobutton': self._singleSelect = 1 self.var = Tkinter.StringVar() self.buttonClass = Tkinter.Radiobutton elif self['buttontype'] == 'checkbutton': self._singleSelect = 0 self.buttonClass = Tkinter.Checkbutton else: raise ValueError, 'bad buttontype option "' + \ self['buttontype'] + \ '": should be button, radiobutton or checkbutton' if self._singleSelect: self.selection = None else: self.selection = [] if self['orient'] not in ('horizontal', 'vertical'): raise ValueError, 'bad orient option ' + repr(self['orient']) + \ ': must be either \'horizontal\' or \'vertical\'' # Check keywords and initialise options. self.initialiseoptions() def getcurselection(self): if self._singleSelect: return self.selection else: return tuple(self.selection) def getvalue(self): return self.getcurselection() def setvalue(self, textOrList): if self._singleSelect: self.__setSingleValue(textOrList) else: # Multiple selections oldselection = self.selection self.selection = textOrList for button in self._buttonList: if button in oldselection: if button not in self.selection: # button is currently selected but should not be widget = self.component(button) if self['buttontype'] == 'checkbutton': widget.deselect() else: # Button widget.configure(relief='raised') else: if button in self.selection: # button is not currently selected but should be widget = self.component(button) if self['buttontype'] == 'checkbutton': widget.select() else: # Button widget.configure(relief='sunken') def numbuttons(self): return len(self._buttonList) def index(self, index): # Return the integer index of the button with the given index. listLength = len(self._buttonList) if type(index) == types.IntType: if index < listLength: return index else: raise ValueError, 'index "%s" is out of range' % index elif index is Pmw.END: if listLength > 0: return listLength - 1 else: raise ValueError, 'RadioSelect has no buttons' else: for count in range(listLength): name = self._buttonList[count] if index == name: return count validValues = 'a name, a number or Pmw.END' raise ValueError, \ 'bad index "%s": must be %s' % (index, validValues) def button(self, buttonIndex): name = self._buttonList[self.index(buttonIndex)] return self.component(name) def add(self, componentName, **kw): if componentName in self._buttonList: raise ValueError, 'button "%s" already exists' % componentName kw['command'] = \ lambda self=self, name=componentName: self.invoke(name) if not kw.has_key('text'): kw['text'] = componentName if self['buttontype'] == 'radiobutton': if not kw.has_key('anchor'): kw['anchor'] = 'w' if not kw.has_key('variable'): kw['variable'] = self.var if not kw.has_key('value'): kw['value'] = kw['text'] elif self['buttontype'] == 'checkbutton': if not kw.has_key('anchor'): kw['anchor'] = 'w' button = apply(self.createcomponent, (componentName, (), 'Button', self.buttonClass, (self._radioSelectFrame,)), kw) if self['orient'] == 'horizontal': self._radioSelectFrame.grid_rowconfigure(0, weight=1) col = len(self._buttonList) button.grid(column=col, row=0, padx = self['padx'], pady = self['pady'], sticky='nsew') self._radioSelectFrame.grid_columnconfigure(col, weight=1) else: self._radioSelectFrame.grid_columnconfigure(0, weight=1) row = len(self._buttonList) button.grid(column=0, row=row, padx = self['padx'], pady = self['pady'], sticky='ew') self._radioSelectFrame.grid_rowconfigure(row, weight=1) self._buttonList.append(componentName) return button def deleteall(self): for name in self._buttonList: self.destroycomponent(name) self._buttonList = [] if self._singleSelect: self.selection = None else: self.selection = [] def __setSingleValue(self, value): self.selection = value if self['buttontype'] == 'radiobutton': widget = self.component(value) widget.select() else: # Button for button in self._buttonList: widget = self.component(button) if button == value: widget.configure(relief='sunken') else: widget.configure(relief='raised') def invoke(self, index): index = self.index(index) name = self._buttonList[index] if self._singleSelect: self.__setSingleValue(name) command = self['command'] if callable(command): return command(name) else: # Multiple selections widget = self.component(name) if name in self.selection: if self['buttontype'] == 'checkbutton': widget.deselect() else: widget.configure(relief='raised') self.selection.remove(name) state = 0 else: if self['buttontype'] == 'checkbutton': widget.select() else: widget.configure(relief='sunken') self.selection.append(name) state = 1 command = self['command'] if callable(command): return command(name, state)