# # Widget implementing functionality similar to that of OptionMenu widget # # The widget defines two components: label and menu, menu being Tkinter's # OptionMenu # # The public methods are: # # get() - returns the current selection # index(name) - returns the integer index of the item 'name' # setitems(items, active = None) # - set's the list of items displayed, selects the item indexed # by 'active' as active (calls the callback too). Otherwise, # first item in the list is selected. # select(index) - selects the item indexed by index. If command option is given, # the command is called # # If an option 'variable' is given, the current value of the menu will be # available via the variable. # # Author Roman Sulzhyk # import Tkinter, Pmw import string # Dummy callback class _dummy: def __init__(self, f, pars): self.f, self.pars = f, pars def __call__(self): apply ( self.f, (self.pars, ) ) class OptionMenu(Pmw.MegaWidget): def __init__(self, parent = None, **kw): # Define the megawidget options. INITOPT = Pmw.INITOPT optiondefs = ( ('labelmargin', 0, INITOPT), ('labelpos', None, INITOPT), ('selectioncommand', '', None), ('items', [], INITOPT ), ('variable', Tkinter.StringVar(''), INITOPT ), ('command', None, None ), ('direction', 'flush', INITOPT ), ) self.defineoptions(kw, optiondefs) # Initialise the base class (after defining the options). Pmw.MegaWidget.__init__(self, parent) # Check that the direction is valid dirs = [ 'left', 'right', 'above', 'below', 'flush' ] if self['direction'] not in dirs: raise ValueError, 'direction is %s, should be one of : %s' % \ ( self['direction'], string.join ( dirs, ', ' )) # A nuisance inherited from OptionMenu if not len(self['items']): raise ValueError, 'items must be a non-empty list' interior = self.interior() # Create OptionMenu self._optionmenu = self.createcomponent('menu', (), None, Tkinter.OptionMenu, (interior, self['variable'], self['items'][0], self['items'][1:]), ) self._optionmenu.configure ( direction = self['direction'],) self._optionmenu.grid ( row = 2, column = 2, sticky='nsew') interior.grid_columnconfigure ( 2, weight = 1) interior.grid_rowconfigure ( 2, weight = 1) # Create the label. self.createlabel(interior) # Re-set the items to register proper callback self.setitems ( self['items'] ) # Check keywords and initialise options. self.initialiseoptions(OptionMenu) #====================================================================== # Public methods def get ( self ): "Return the name of the menu item currently selected" return self['variable'].get() def setitems ( self, items, active = None ): "Set the list of items to be displayed" m = self._optionmenu['menu'] m.delete ( 0, 'end' ) for i in items: m.add_command ( label = i, command = _dummy ( self._callback, i )) if active: self.select(active) else: self.select(items[0]) def index ( self, name ): "Return integer index of item with name 'name'" return self._optionmenu['menu'].index(name) def select ( self, index ): "Select the item with index" ind = self.index ( index ) val = self._optionmenu['menu'].entrycget(ind, 'label') self['variable'].set(val) # Note that the callback is called: if callable ( self['command'] ): apply ( self['command'], (val, ) ) #====================================================================== # Private methods def _callback ( self, tag ): "Called when user selects an item" self['variable'].set(tag) if callable ( self['command'] ): apply ( self['command'], (tag, ) )