#! /usr/env/python #-------------------------------------------------------------------------------- """ MultiShell provides a GUI application framework. This is a streamlined adaptation of GuiAppD.py, originally created by Doug Hellmann (doughellmann@mindspring.com). """ #-------------------------------------------------------------------------------- # # Revised 19-Sep-2008 : remove all instannce of "binding" the help message to the cursor # #-------------------------------------------------------------------------------- from Tkinter import * import Pmw import sys, string import ProgressBar from FileSelectDialog import FileSelectDialog from Print_Utils import printLine from Print_Utils import flushLogFile #-------------------------------------------------------------------------------- #-------------------------------------------------------------------------------- # Set the dimensions of the file select dialog window SelectFileWindowWidth = 400 SelectFileWindowHeight = 300 kludge_fixComboBox = "yes" # "yes" = reverse order (first vs. last) in the comboBox between # value returned by comboBox.list.index() # and the value specified to comboBox.selectitem() # why this is needed is not understood #-------------------------------------------------------------------------------- #-------------------------------------------------------------------------------- class MultiShell(Pmw.MegaWidget): appversion = '1.0' appname = 'Generic Application Frame' copyright = 'Copyright YYYY Your Company. All Rights Reserved' contactname = 'Your Name' contactphone = '(999) 555-1212' contactemail = 'youremail@host.com' frameWidth = 450 frameHeight = 320 padx = 5 pady = 5 usecommandarea = 0 balloonhelp = 1 frameName = [] ManFrame = 0 ; frameName.append ( "Main" ) # Main is last as totFrame gets adjusted below totFrame = ManFrame + 1 # total number of dialog frames curFrame = ManFrame # dialog frame to display at startup = main busyCursor = 'watch' totalFieldRows = 0 def __init__( self, **kw ): optiondefs = ( ('padx', 1, Pmw.INITOPT), ('pady', 1, Pmw.INITOPT), ('framewidth', 1, Pmw.INITOPT), ('frameheight', 1, Pmw.INITOPT), ('usecommandarea', self.usecommandarea, Pmw.INITOPT)) self.defineoptions(kw, optiondefs) self.root = Tk() self.initializeTk(self.root) Pmw.initialise(self.root) self.root.title(self.appname) self.root.geometry('%dx%d' % (self.frameWidth, self.frameHeight)) # Initialize the base class Pmw.MegaWidget.__init__(self, parent=self.root) # initialize the application self.appInit() # create the interface self.__createInterface() # create a table to hold the cursors for # widgets which get changed when we go busy self.preBusyCursors = None # pack the container and set focus # to ourselves self._hull.pack(side=TOP, fill=BOTH, expand=YES) self.focus_set() # initialize our options self.initialiseoptions(MultiShell) # create a file selection dialog self.SelectDialog = FileSelectDialog ( self.interior(), width = SelectFileWindowWidth, height = SelectFileWindowHeight ) def appInit(self): # Called before interface is created (should be overridden). pass def initializeTk(self, root): # Initialize platform-specific options if sys.platform == 'mac': self.__initializeTk_mac(root) elif sys.platform == 'win32': self.__initializeTk_win32(root) else: self.__initializeTk_unix(root) def __initializeTk_colors_common(self, root): root.option_add('*background', 'grey') root.option_add('*foreground', 'black') root.option_add('*EntryField.Entry.background', 'white') root.option_add('*Entry.background', 'white') root.option_add('*MessageBar.Entry.background', 'gray85') root.option_add('*Listbox*background', 'white') root.option_add('*Listbox*selectBackground', 'dark slate blue') root.option_add('*Listbox*selectForeground', 'white') def __initializeTk_win32(self, root): self.__initializeTk_colors_common(root) root.option_add('*Font', 'Verdana 10 bold') root.option_add('*EntryField.Entry.Font', 'Courier 10') root.option_add('*Listbox*Font', 'Courier 10') def __initializeTk_mac(self, root): self.__initializeTk_colors_common(root) def __initializeTk_unix(self, root): self.__initializeTk_colors_common(root) def busyStart(self, newcursor=None): if not newcursor: newcursor = self.busyCursor newPreBusyCursors = {} for component in self.busyWidgets: newPreBusyCursors[component] = component['cursor'] component.configure(cursor=newcursor) component.update_idletasks() self.preBusyCursors = (newPreBusyCursors, self.preBusyCursors) def busyEnd(self): if not self.preBusyCursors: return oldPreBusyCursors = self.preBusyCursors[0] self.preBusyCursors = self.preBusyCursors[1] for component in self.busyWidgets: try: component.configure(cursor=oldPreBusyCursors[component]) except KeyError: pass component.update_idletasks() def __createAboutBox(self): Pmw.aboutversion(self.appversion) Pmw.aboutcopyright(self.copyright) Pmw.aboutcontact( 'For more information, contact:\n %s\n Phone: %s\n Email: %s' %\ (self.contactname, self.contactphone, self.contactemail)) self.about = Pmw.AboutDialog(self._hull, applicationname=self.appname) self.about.withdraw() return None def showAbout(self): # Create the dialog to display about and contact information. self.about.show() self.about.focus_set() def toggleBalloon(self): if self.toggleBalloonVar.get(): self.__balloon.configure(state = 'both') else: self.__balloon.configure(state = 'status') def __createMenuBar(self): self.menuBar = self.createcomponent('menubar', (), None, Pmw.MenuBar, (self._hull,), hull_relief=RAISED, hull_borderwidth=1, balloon=self.balloon()) self.menuBar.pack(fill=X) self.menuBar.addmenu('Help', 'About %s' % self.appname, side='right') self.menuBar.addmenu('File', 'File commands and Quit') def createMenuBar(self): self.menuBar.addmenuitem('Help', 'command', 'Get information on application', label='About...', command=self.showAbout) self.toggleBalloonVar = IntVar() self.toggleBalloonVar.set(1) self.menuBar.addmenuitem('Help', 'checkbutton', 'Toggle balloon help', label='Balloon help', variable = self.toggleBalloonVar, command=self.toggleBalloon) self.menuBar.addmenuitem('File', 'command', 'Quit this application', label='Quit', command=self.quit) def __createBalloon(self): # Create the balloon help manager for the frame. # Create the manager for the balloon help self.__balloon = self.createcomponent('balloon', (), None, Pmw.Balloon, (self._hull,)) if not self.balloonhelp : self.__balloon.configure(state = 'status') def balloon(self): return self.__balloon def __createDataArea(self): # Create data area where data entry widgets are placed. self.dataArea = [None] * self.totFrame for nFrame in range (self.totFrame) : self.dataArea[nFrame] = self.createcomponent('dataarea%d' % nFrame, (), None, Frame, (self._hull,), relief=GROOVE, bd=1) if nFrame == self.curFrame : self.dataArea[nFrame].pack(side=TOP, fill=BOTH, expand=YES, padx=self['padx'], pady=self['pady']) else : self.dataArea[nFrame].forget() def selectDataArea(self, nFrame): # switch to a different data area if nFrame < 0 : nFrame = 0 if nFrame >= self.totFrame : nFrame = self.totFrame - 1 self.curFrame = nFrame for nFrame in range (self.totFrame) : if nFrame == self.curFrame : self.dataArea[nFrame].pack(side=TOP, fill=BOTH, expand=YES, padx=self['padx'], pady=self['pady']) else : self.dataArea[nFrame].forget() def __createCommandArea(self): # Create a command area for application-wide buttons. self.__commandFrame = self.createcomponent('commandframe', (), None, Frame, (self._hull,), relief=SUNKEN, bd=1) self.__buttonBox = self.createcomponent('buttonbox', (), None, Pmw.ButtonBox, (self.__commandFrame,), padx=0, pady=5) self.__buttonBox.pack(side=TOP, expand=NO, fill=X) self.__buttonBox._hull.configure(bg='grey85') if self['usecommandarea']: self.__commandFrame.pack(side=BOTTOM, expand=NO, fill=X, padx=self['padx'], pady=self['pady']) def __createMessageBar(self): # Create the message bar area for help and status messages. frame = self.createcomponent('bottomtray', (), None, Frame,(self._hull,), relief=SUNKEN) self.__messageBar = self.createcomponent('messagebar', (), None, Pmw.MessageBar, (frame,), #entry_width = 40, entry_relief=SUNKEN, entry_bd=1, labelpos=None) self.__messageBar.pack(side=LEFT, expand=YES, fill=X) self.__progressBar = ProgressBar.ProgressBar(frame, fillColor='slateblue', doLabel=1, width=150) self.__progressBar.frame.pack(side=LEFT, expand=NO, fill=NONE) self.updateProgress(0) frame.pack(side=BOTTOM, expand=NO, fill=X) self.__balloon.configure(statuscommand = \ self.__messageBar.helpmessage) def messageBar(self): return self.__messageBar def updateProgress(self, newValue=0, newMax=0): self.__progressBar.updateProgress(newValue, newMax) def bind(self, child, balloonHelpMsg, statusHelpMsg=None): # Bind a help message and/or status message to a widget. self.__balloon.bind(child, balloonHelpMsg, statusHelpMsg) def interior(self, nFrame = 0 ): # Retrieve the interior site where widgets should go. return self.dataArea[nFrame] def buttonBox(self): # Retrieve the button box. return self.__buttonBox def buttonAdd(self, buttonName, helpMessage=None, statusMessage=None, **kw): # Add a button to the button box. newBtn = self.__buttonBox.add(buttonName) newBtn.configure(kw) # if helpMessage: # self.bind(newBtn, helpMessage, statusMessage) return newBtn #-------------------------------------------------------------------------------- def addFieldEntry(self, labelName=None, frame=None, nFrame=0, helpMessage=None, statusMessage=None, initValue=None, row=None, rowspan=1, column=None, columnspan=1, command=None, **kw): if ( frame == None ) : frame = self.dataArea[nFrame] if ( row == None ) : row = self.nextFieldRow ( ) if ( column == None ) : column = 1 if ( labelName != None ) : self.addFieldLabel( labelName=labelName, frame=frame, helpMessage=None, statusMessage=None, rowspan=rowspan, column=column, row=row ) column = column + 1 newEntry = Pmw.EntryField(frame, modifiedcommand=command ) # entryVar = StringVar() # newEntry['textvariable'] = entryVar # newEntry.configure(kw) newEntry.component('entry').config(kw) newEntry.setentry(initValue) newEntry.grid( row=row, rowspan=rowspan, column=column, columnspan=columnspan, padx=5, pady=5, sticky=W ) # entryVar.set ( initValue ) # if helpMessage: self.bind(newEntry, helpMessage, statusMessage) # return entryVar return newEntry def addFieldCombo(self, labelName, frame=None, nFrame=0, helpMessage=None, statusMessage=None, initValue='', row=None, column=None, rowspan=1, columnspan=1, gridPadx=5, gridPady=5, command=None, **kw): if ( row == None ) : row = self.nextFieldRow ( ) if ( column == None ) : column = 1 self.addFieldLabel( labelName=labelName, nFrame=nFrame, helpMessage=None, statusMessage=None, rowspan=rowspan, column=column, row=row, gridPadx=gridPadx, gridPady=gridPady ) if ( frame == None ) : frame = self.dataArea[nFrame] newCombo = Pmw.ComboBox( frame ) newCombo.component('entry').config(kw) newCombo.component('entryfield').configure( modifiedcommand=command ) newCombo.grid( row=row, rowspan=rowspan, column=column+1, columnspan=columnspan, padx=gridPadx, pady=gridPady, sticky=W ) newCombo.list = [ ] if initValue : newCombo.insert( 0, initValue ) newCombo.selectitem ( 0 ) newCombo.list.append ( initValue ) # if helpMessage: self.bind(newCombo, helpMessage, statusMessage) return newCombo def addFieldLabel(self, labelName=None, frame=None, nFrame=0, helpMessage=None, statusMessage=None, row=0, column=0, rowspan=1, columnspan=1, gridPadx=5, gridPady=5, gridSticky=E, **kw): if ( frame == None ) : frame = self.dataArea[nFrame] newLabel = Label( frame, text=labelName) newLabel.configure(kw) newLabel.grid( column=column, row=row, rowspan=rowspan, columnspan=columnspan, padx=gridPadx, pady=gridPady, sticky=gridSticky ) # if helpMessage: self.bind(newLabel, helpMessage, statusMessage) return newLabel def addFieldButton(self, labelName, frame=None, nFrame=0, helpMessage=None, statusMessage=None, row=0, rowspan=1, column=0, columnspan=1, gridSticky=E, **kw): if ( frame == None ) : frame = self.dataArea[nFrame] newButton = Button( frame, text=labelName) newButton.configure(kw) newButton.grid( column=column, row=row, columnspan=columnspan, rowspan=rowspan, padx=5, pady=5, sticky=gridSticky ) # if helpMessage: self.bind(newButton, helpMessage, statusMessage) return newButton def addFieldCheckB(self, labelName, variable, frame=None, nFrame=0, helpMessage=None, statusMessage=None, row=0, column=0, columnspan=1, gridPadx=5, gridPady=5, **kw): if ( frame == None ) : frame = self.dataArea[nFrame] newCheckB = Checkbutton(frame, text=labelName, variable=variable) newCheckB.configure(kw) newCheckB.grid( column=column, row=row, columnspan=columnspan, padx=gridPadx, pady=gridPady, sticky=W ) # if helpMessage: self.bind(newCheckB, helpMessage, statusMessage) return newCheckB def addFieldRadioB(self, labelName, frame, variable, value, helpMessage=None, statusMessage=None, row=0, column=-1, columnspan=1, gridPadx=1, gridPady=1, **kw): newRadioB = Radiobutton(frame, text=labelName, value=value, variable=variable) newRadioB.configure(kw) if ( column == -1 ) : newRadioB.pack( side=LEFT, anchor=W, padx=gridPadx, pady=gridPady ) else: newRadioB.grid( column=column, row=row, columnspan=columnspan, padx=gridPadx, pady=gridPady, sticky=W ) # if helpMessage: self.bind(newRadioB, helpMessage, statusMessage) return newRadioB def addFieldFrame (self, labelName, frame=None, nFrame=0, helpMessage=None, statusMessage=None, row=0, column=0, columnspan=1, **kw): if ( frame == None ) : frame = self.dataArea[nFrame] newFrame = self.createcomponent (labelName, (), None, Frame, (frame,), relief=GROOVE, bd=1) newFrame.configure(kw) newFrame.grid( column=column, row=row, columnspan=columnspan, padx=5, pady=5, sticky=W ) # if helpMessage: self.bind(newFrame, helpMessage, statusMessage) return newFrame def nextFieldRow ( self ) : self.totalFieldRows += 1 return self.totalFieldRows def currentFieldRow ( self ) : return self.totalFieldRows #-------------------------------------------------------------------------------- def __createInterface(self): self.__createBalloon() self.__createMenuBar() self.__createDataArea() self.__createCommandArea() self.__createMessageBar() self.__createAboutBox() # # Create the parts of the interface # which can be modified by subclasses # self.busyWidgets = ( self.root, ) self.createMenuBar() self.createInterface() def createInterface(self): # Override this method to create the interface for the app. pass def main(self): # This method should be left intact! self.pack() self.mainloop() def run(self): self.main() #-------------------------------------------------------------------------------- def selectFrame ( self, nFrame ) : if ( nFrame == self.ManFrame ) : printLine ( ) printLine ( "...", "switch to %s dialog" % self.frameName[nFrame] ) self.selectDataArea ( nFrame ) flushLogFile () #-------------------------------------------------------------------------------- def Find_File ( self, ComboBox = None ): SelectedFile = self.SelectDialog.GetName () printLine ( "Select", SelectedFile ) if ( ComboBox != None ) : updateComboBox ( ComboBox, SelectedFile ) return SelectedFile #-------------------------------------------------------------------------------- #-------------------------------------------------------------------------------- def updateComboBox ( comboBox, entry_str = None ) : if ( entry_str == None ) : entry_str = comboBox.get() if comboBox.__dict__.has_key('list') : if ( entry_str not in comboBox.list ) : comboBox.list.append ( entry_str ) comboBox.insert( 0, entry_str ) comboBox.selectitem( 0 ) else : if ( kludge_fixComboBox == "yes" ) : comboBox.selectitem( len(comboBox.list) - comboBox.list.index ( entry_str ) - 1 ) else : comboBox.selectitem( comboBox.list.index ( entry_str ) ) try : entry_int = eval ( string.replace ( str(entry_str), ' ', '' ) ) except : entry_int = 0 return entry_int #-------------------------------------------------------------------------------- def updateIntVar ( intVar, entry_int = None ) : if ( entry_int == None ) : entry_int = intVar.get() else : entry_int = int(entry_int) intVar.set(entry_int) return entry_int #-------------------------------------------------------------------------------- def updateIntVarStr ( intVar, entry_str, entry_array ) : if ( entry_str == None ) : # no value given, so retrieve from the integer variable # associated with the radio button entry_int = intVar.get() # retrieve the string associated with this value entry_str = entry_array[entry_int] else : # try to get the integer index corresponding to this string if ( entry_str in entry_array ) : entry_int = entry_array.index(entry_str) else : entry_int = 0 # set the variable accordingly to update the radio button intVar.set(entry_int) return entry_str #-------------------------------------------------------------------------------- #-------------------------------------------------------------------------------- class TestMultiShell(MultiShell): usecommandarea=1 def createButtons(self): self.buttonAdd('Ok', helpMessage='Exit(balloon)', statusMessage='Exit(status)', command=self.quit) def createMain(self): self.label = self.addFieldLabel('Data Area') self.label.pack() self.bind(self.label, 'Space taker') def createInterface(self): MultiShell.createInterface(self) self.createButtons() self.createMain() if __name__ == '__main__': test = TestMultiShell() test.run()