def __initialiseDigitPanel(self, base, row=__DIGIT_ROW, col=__DIGIT_COL, digitsPerRow=__DIGITS_PER_ROW): appendee = self.__iopanel self.__base = base self.__positioner = GridPositioner(row=row, col=col, columns=digitsPerRow) for digit in [digit for digit in range(1, base)] + [0]: button = Digit(master=self, digit=digit, appendee=appendee) self.__positioner.add(button) # Adds a button for the clear function. self.__addSpecialDigitPanelButton(text=Calculator.__CLEAR_TITLE, command=self.__onClearButtonClick) # Adds a button for the push function. self.__addSpecialDigitPanelButton(text=Calculator.__PUSH_TITLE, command=self.__onPushButtonClick) # Adds a button for the addition function. self.__addSpecialDigitPanelButton(text=Calculator.__ADD_TITLE, command=self.__onAddButtonClick) # Adds a button for the subtraction function. self.__addSpecialDigitPanelButton(text=Calculator.__SUB_TITLE, command=self.__onSubButtonClick) # Adds a button for the multiplication function. self.__addSpecialDigitPanelButton(text=Calculator.__MUL_TITLE, command=self.__onMulButtonClick) # Adds a button for the division function. self.__addSpecialDigitPanelButton(text=Calculator.__DIV_TITLE, command=self.__onDivButtonClick) # Adds a button for the unary minus function. self.__addSpecialDigitPanelButton(text=Calculator.__UMIN_TITLE, command=self.__onUMinButtonClick)
def __initialiseDigitPanel(self, base, row=__DIGIT_ROW, col=__DIGIT_COL, digitsPerRow=__DIGITS_PER_ROW): appendee = self.__iopanel self.__base = base self.__positioner = GridPositioner(row=row, col=col, columns=digitsPerRow) for digit in [digit for digit in range(1, base)] + [0]: button = Digit(master=self, digit=digit, appendee=appendee) self.__positioner.add(button) self.__addSpecialDigitPanelButton(text=Calculator.__CLEAR_TITLE, command=self.__onClearButtonClick) self.__addSpecialDigitPanelButton(text=Calculator.__PUSH_TITLE, command=self.__onPushButtonClick)
def __initialiseDigitPanel( self, base, row=__DIGIT_ROW, col=__DIGIT_COL, digitsPerRow=__DIGITS_PER_ROW ) : appendee = self.__iopanel self.__base = base self.__positioner = GridPositioner( row=row, col=col, columns=digitsPerRow ) for digit in [ digit for digit in range( 1, base ) ] + [ 0 ] : button = Digit( master=self, digit=digit, appendee=appendee ) self.__positioner.add( button ) self.__addSpecialDigitPanelButton( text=Calculator.__CLEAR_TITLE, command=self.__onClearButtonClick ) self.__addSpecialDigitPanelButton( text=Calculator.__PUSH_TITLE, command=self.__onPushButtonClick )
class Calculator(Tk): # Width of @IOPanel@ in pixels. __IO_PANEL_WIDTH = 200 # Height of @IOPanel@ in pixels. __IO_PANEL_HEIGHT = 50 # Row number of @IOPanel@ in grid layout of the calculator. __IO_PANEL_ROW = 0 # Column number of @IOPanel@ in grid layout of the calculator. __IO_PANEL_COL = 0 # Span of @IOPanel@ in widgets in the grid layout of the calculator. __IO_PANEL_SPAN = 3 # The number base of the calculator. __BASE = 10 # The title of this calculator's window. __TITLE = "Calculator" # Row number of the first digit row in grid layout of the calculator. __DIGIT_ROW = 1 # Column number of the first digit row in grid layout of the calculator. __DIGIT_COL = 0 # Number of digit buttons per row in grid layout of the calculator. __DIGITS_PER_ROW = 3 # Text on the clear button. __CLEAR_TITLE = "C" # Text on the push button. __PUSH_TITLE = "P" # Main constructor. # @parent@: The master widget of this @Calculator@ or @None@ # @base@: The number base for this @Calculator@. def __init__(self, master, title=__TITLE, base=__BASE): # Initialise main calculator window. Tk.__init__(self, master) # Set title. self.title(title) # Save @master@. Not used... self.__master = master # Finish rest of initialisation. self.__initialise(base=base) # YOU SHOULD REMOVE THIS. IT'S FOR DEMONSTRATING THE API. self.__iopanel.set("HI") # Utility method for initialising this @Calculator@'s components. # @base@: the number base of this @Calculator@'s operations. def __initialise(self, base): # Initialise the IO panel component. self.__initialiseIOPanel() # Initialise the digit panel component. self.__initialiseDigitPanel(base=base) # Initialise the digit panel widget of this @Calculator@. # @base@: the number base of this @Calculator@'s operations. # @row@: row number in grid layout of this @Calculator@. # @col@: column number in grid layout of this @Calculator@. # @digitsPerRow@: digits per row in grid layout of this @Calculator@. def __initialiseDigitPanel(self, base, row=__DIGIT_ROW, col=__DIGIT_COL, digitsPerRow=__DIGITS_PER_ROW): appendee = self.__iopanel self.__base = base self.__positioner = GridPositioner(row=row, col=col, columns=digitsPerRow) for digit in [digit for digit in range(1, base)] + [0]: button = Digit(master=self, digit=digit, appendee=appendee) self.__positioner.add(button) self.__addSpecialDigitPanelButton(text=Calculator.__CLEAR_TITLE, command=self.__onClearButtonClick) self.__addSpecialDigitPanelButton(text=Calculator.__PUSH_TITLE, command=self.__onPushButtonClick) # Utility method for adding additional button to the digit panel. # @text@: the text on the button. # @command@: the button's callback method. def __addSpecialDigitPanelButton(self, text, command): button = Button(master=self, text=text, command=command) self.__positioner.add(button) # Initialise the IO panel widget of this @Calculator@. def __initialiseIOPanel(self): width = Calculator.__IO_PANEL_WIDTH height = Calculator.__IO_PANEL_HEIGHT # create the IO panel. iopanel = IOPanel(master=self, width=width, height=height) row = Calculator.__IO_PANEL_ROW col = Calculator.__IO_PANEL_COL span = Calculator.__IO_PANEL_SPAN # Add the IO panel to the current crid layout. iopanel.grid(row=row, column=col, columnspan=span) # Save object reference to the IO panel for future use. self.__iopanel = iopanel # Callback method for push button def __onPushButtonClick(self): # REMOVE THE NEXT STATEMENT. IT'S ONLY HERE TO SHOW YOU # HOW TO GET THE TEXT IN THE INPUT FIELD. print(self.__iopanel.get()) self.__iopanel.reset() # Callback method for clear button def __onClearButtonClick(self): self.__iopanel.reset()
class Calculator( Tk ) : # Width of @IOPanel@ in pixels. __IO_PANEL_WIDTH = 200 # Height of @IOPanel@ in pixels. __IO_PANEL_HEIGHT = 50 # Row number of @IOPanel@ in grid layout of the calculator. __IO_PANEL_ROW = 0 # Column number of @IOPanel@ in grid layout of the calculator. __IO_PANEL_COL = 0 # Span of @IOPanel@ in widgets in the grid layout of the calculator. __IO_PANEL_SPAN = 3 # The default base of the calculator. __BASE = 10 # The title of this calculator's window. __TITLE = "Calculator" #The title of the Base selection menu __BASE_MENU_TITLE = 'Base' #The title of the Help menu __HELP_MENU_TITLE = 'Help' #The title of the Options Menu __OPTIONS_MENU_TITLE = "Options" # Row number of the first digit row in grid layout of the calculator. __DIGIT_ROW = 1 # Column number of the first digit row in grid layout of the calculator. __DIGIT_COL = 0 # Number of digit buttons per row in grid layout of the calculator. __DIGITS_PER_ROW = 3 # Text on the clear button. __CLEAR_TITLE = "C" # Text on the push button. __PUSH_TITLE = "P" #The operator for Clear Everything button __CLEAR_EVERYTHING_TITLE = 'CE' #Sticky for the stack panel __STACK_STICKY = 'NS' #String for recognising errors from operations __ERROR_TAG = 'Error' # Main constructor. # @parent@: The master widget of this @Calculator@ or @None@ # @base@: The number base for this @Calculator@. def __init__( self, master, title=__TITLE, base=__BASE) : self.__base = base #INITIALIZE THE STACK self.__stack = Stack() #Initialise the Operation class self.__operation = Operation(self.__stack) # Initialise main calculator window. Tk.__init__( self, master ) # Set title. self.title( title ) #Set not resizable self.resizable(0,0) # Save @master@. Not used... self.__master = master # Finish rest of initialisation. self.__initialise( base=base) # Utility method for initialising this @Calculator@'s components. # @base@: the number base of this @Calculator@'s operations. def __initialise( self, base,clearOption=CLEAR_STACK_DEFAULT, displayOption=DISPLAY_STACK_DEFAULT) : self.__clearStack = clearOption self.__displayStack = displayOption # Initialise the IO panel component. self.__initialiseIOPanel( ) # Initialise the digit panel component. self.__initialiseDigitPanel( base=base) #Initialise the operand panel component self.__initialiseOperandPanel() #Initialise the menu bar self.__initialiseMenu() #Add the Base Change dropdown self.__initialiseBaseMenu(base) #Add the Options dropdown self.__initialiseOptionsMenu() #Add the Help dropdown self.__initialiseHelpMenu() #Initialise the stack display panel, if the option is selected if self.__displayStack: self.__initialiseStackPanel() # Initialise the digit panel widget of this @Calculator@. # @base@: the number base of this @Calculator@'s operations. # @row@: row number in grid layout of this @Calculator@. # @col@: column number in grid layout of this @Calculator@. # @digitsPerRow@: digits per row in grid layout of this @Calculator@. def __initialiseDigitPanel( self, base, row=__DIGIT_ROW, col=__DIGIT_COL, digitsPerRow=__DIGITS_PER_ROW ) : appendee = self.__iopanel self.__base = base self.__positioner = GridPositioner( row=row, col=col, columns=digitsPerRow ) for digit in [ digit for digit in range( 1, base ) ] + [ 0 ] : button = Digit( master=self, digit=digit, appendee=appendee ) self.__positioner.add( button ) self.__addSpecialDigitPanelButton( text=Calculator.__CLEAR_TITLE, command=self.__onClearButtonClick ) self.__addSpecialDigitPanelButton( text=Calculator.__PUSH_TITLE, command=self.__onPushButtonClick ) # Utility method for adding additional button to the digit panel. # @text@: the text on the button. # @command@: the button's callback method. def __addSpecialDigitPanelButton( self, text, command ) : button = Button( master=self, text=text, command=command ) self.__positioner.add( button ) # Initialise the IO panel widget of this @Calculator@. def __initialiseIOPanel( self ) : width = Calculator.__IO_PANEL_WIDTH height = Calculator.__IO_PANEL_HEIGHT # create the IO panel. iopanel = IOPanel( master=self, width=width, height=height ) row = Calculator.__IO_PANEL_ROW col = Calculator.__IO_PANEL_COL span = Calculator.__IO_PANEL_SPAN # Add the IO panel to the current crid layout. iopanel.grid( row=row, column=col, columnspan=span ) # Save object reference to the IO panel for future use. self.__iopanel = iopanel def __initialiseOperandPanel( self ): #Add the Operand buttons to the panel operators = OPERATORS for operand in operators: command = lambda operand=operand:self.__onOperandButtonClick( operand) self.__addSpecialDigitPanelButton(operand, command) #Add the Clear Everything Button title = Calculator.__CLEAR_EVERYTHING_TITLE self.__addSpecialDigitPanelButton(title, self.__onClearEverythingButtonClick) def __initialiseMenu(self): #Initialises the menu bar self.__menu = Menu(self) self.config(menu=self.__menu) def __initialiseBaseMenu(self, base) : #Create the dropdown for selecting the base and add it to the #menu baseDropDown = BaseMenu(self, base) label = Calculator.__BASE_MENU_TITLE self.__menu.add_cascade(label=label, menu=baseDropDown) def __initialiseOptionsMenu(self): self.__options = OptionMenu(self, self.__clearStack, self.__displayStack) label = Calculator.__OPTIONS_MENU_TITLE self.__menu.add_cascade(label=label, menu=self.__options) def __initialiseHelpMenu(self): #Initialises the panel for giving help options. ie. instructions helpMenu = HelpMenu(self) label = Calculator.__HELP_MENU_TITLE self.__menu.add_cascade(label=label,menu=helpMenu) def __initialiseStackPanel(self): #Initialises the side panel that displays the current stack. height = Calculator.__IO_PANEL_HEIGHT width = Calculator.__IO_PANEL_WIDTH self.__stackPanel = StackPanel(master=self,height=height,width=width, stack=self.__stack) self.__showStack() def __showStack(self) : #A method for adding the stack panel to the window #This gets the last row used in the window rows = ceil(self.__positioner.addedWidgets / Calculator.__DIGITS_PER_ROW) + 1 sticky = Calculator.__STACK_STICKY row = Calculator.__IO_PANEL_ROW col = Calculator.__DIGITS_PER_ROW + 1 #Next to the rest of the stuff self.__stackPanel.grid(row=row, column=col, rowspan=rows, sticky=sticky) self.__stackPanel.update() def __hideStack(self) : #A method for hiding the stack panel self.__stackPanel.grid_forget() def onStackDisplayChange(self) : #A method for handling when the user changes the display stack option displayStack = self.__options.displayStack.get() if displayStack : #The stack is hidden, we need to add it back to view self.__showStack() else : #The stack is already visible, hide it self.__hideStack() # Callback method for push button def __onPushButtonClick( self ) : self.__pushInput() def __pushInput(self) : #push the value of the input field onto the stack var = self.__iopanel.get( ) if var != "": self.__stack.push(var) self.__stackPanel.update() self.__iopanel.reset( ) # Callback method for clear button def __onClearButtonClick( self ) : self.__iopanel.reset( ) #Handle presses of operand buttons def __onOperandButtonClick(self, operand) : #Handle the clicking of operand buttons #Push any input in the field onto the stack, if any self.__pushInput() #Run the apply function, then display the answer answer = self.__operation.apply(operand,self.__base) if answer != None : #We don't want to display None in the output field self.__iopanel.set(answer) if Calculator.__ERROR_TAG in answer : #If the last operation gave us an error, #we want to remove it from the stack self.__stack.pop() self.__stackPanel.update() def changeBase(self, newBase) : #Changes between the given bases self.__removeAllChildren() clearStack = self.__options.clearStack.get() displayStack = self.__options.displayStack.get() self.__stack.clear() if clearStack else self.__operation.convertStack( self.__stack,newBase,self.__base) self.__initialise(newBase,clearStack,displayStack) def __removeAllChildren(self) : #Removes all the children from self for widget in self.winfo_children() : #Destroy all widgets in self, without destroying self widget.destroy() def __onClearEverythingButtonClick(self): #clear the stack self.__stack.clear() self.__iopanel.set("") self.__stackPanel.update() self.__iopanel.reset()
class Calculator(Tk): # Width of @IOPanel@ in pixels. __IO_PANEL_WIDTH = 200 # Height of @IOPanel@ in pixels. __IO_PANEL_HEIGHT = 50 # Row number of @IOPanel@ in grid layout of the calculator. __IO_PANEL_ROW = 0 # Column number of @IOPanel@ in grid layout of the calculator. __IO_PANEL_COL = 0 # Span of @IOPanel@ in widgets in the grid layout of the calculator. __IO_PANEL_SPAN = 3 # The number base of the calculator. __BASE = 10 # The title of this calculator's window. __TITLE = "Calculator" # Row number of the first digit row in grid layout of the calculator. __DIGIT_ROW = 1 # Column number of the first digit row in grid layout of the calculator. __DIGIT_COL = 0 # Number of digit buttons per row in grid layout of the calculator. __DIGITS_PER_ROW = 3 # Text on the clear button. __CLEAR_TITLE = "C" # Text on the push button. __PUSH_TITLE = "P" # Text on the add button. __ADD_TITLE = "+" # Text on the substraction button. __SUB_TITLE = "-" # Text on the multiplication button. __MUL_TITLE = "*" # Text on the division button. __DIV_TITLE = "/" # Text on the unary minus button. __UMIN_TITLE = "(-)" # Main constructor. # @parent@: The master widget of this @Calculator@ or @None@ # @base@: The number base for this @Calculator@. def __init__(self, master, title=__TITLE, base=__BASE): # Initialise main calculator window. Tk.__init__(self, master) # Set title. self.title(title) # Save @master@. Not used... self.__master = master # Finish rest of initialisation. self.__initialise(base=base) # YOU SHOULD REMOVE THIS. IT'S FOR DEMONSTRATING THE API. #self.__iopanel.set( "HI" ) # Utility method for initialising this @Calculator@'s components. # @base@: the number base of this @Calculator@'s operations. def __initialise(self, base): # Initialise the IO panel component. self.__initialiseIOPanel() # Initialise the digit panel component. self.__initialiseDigitPanel(base=base) stack = Stack() self.stack = stack # Initialise the digit panel widget of this @Calculator@. # @base@: the number base of this @Calculator@'s operations. # @row@: row number in grid layout of this @Calculator@. # @col@: column number in grid layout of this @Calculator@. # @digitsPerRow@: digits per row in grid layout of this @Calculator@. def __initialiseDigitPanel(self, base, row=__DIGIT_ROW, col=__DIGIT_COL, digitsPerRow=__DIGITS_PER_ROW): appendee = self.__iopanel self.__base = base self.__positioner = GridPositioner(row=row, col=col, columns=digitsPerRow) for digit in [digit for digit in range(1, base)] + [0]: button = Digit(master=self, digit=digit, appendee=appendee) self.__positioner.add(button) # Adds a button for the clear function. self.__addSpecialDigitPanelButton(text=Calculator.__CLEAR_TITLE, command=self.__onClearButtonClick) # Adds a button for the push function. self.__addSpecialDigitPanelButton(text=Calculator.__PUSH_TITLE, command=self.__onPushButtonClick) # Adds a button for the addition function. self.__addSpecialDigitPanelButton(text=Calculator.__ADD_TITLE, command=self.__onAddButtonClick) # Adds a button for the subtraction function. self.__addSpecialDigitPanelButton(text=Calculator.__SUB_TITLE, command=self.__onSubButtonClick) # Adds a button for the multiplication function. self.__addSpecialDigitPanelButton(text=Calculator.__MUL_TITLE, command=self.__onMulButtonClick) # Adds a button for the division function. self.__addSpecialDigitPanelButton(text=Calculator.__DIV_TITLE, command=self.__onDivButtonClick) # Adds a button for the unary minus function. self.__addSpecialDigitPanelButton(text=Calculator.__UMIN_TITLE, command=self.__onUMinButtonClick) # Utility method for adding additional button to the digit panel. # @text@: the text on the button. # @command@: the button's callback method. def __addSpecialDigitPanelButton(self, text, command): button = Button(master=self, text=text, command=command) self.__positioner.add(button) # Initialise the IO panel widget of this @Calculator@. def __initialiseIOPanel(self): width = Calculator.__IO_PANEL_WIDTH height = Calculator.__IO_PANEL_HEIGHT # create the IO panel. iopanel = IOPanel(master=self, width=width, height=height) row = Calculator.__IO_PANEL_ROW col = Calculator.__IO_PANEL_COL span = Calculator.__IO_PANEL_SPAN # Add the IO panel to the current crid layout. iopanel.grid(row=row, column=col, columnspan=span) # Save object reference to the IO panel for future use. self.__iopanel = iopanel # Callback method for push button. def __onPushButtonClick(self): if self.__iopanel.get() != None: #if the base is between 2 - 9, convert it to base ten. if self.__base in range(2, 9): self.stack.push( self.stack.convertToDecimal(self.__iopanel.get(), self.__base)) #if the base is 10 then push it to the stack. else: self.stack.push(self.__iopanel.get()) # Clear the iopanel input. self.__iopanel.reset() # Callback method for clear button. def __onClearButtonClick(self): self.__iopanel.reset() # Callback method for push button. def __onAddButtonClick(self): self.__iopanel.reset() # Sets the output to the added result. self.__iopanel.set(self.stack.add(self.__base)) # Callback method for subtraction button. def __onSubButtonClick(self): self.__iopanel.reset() # Sets the output to the subtracted result. self.__iopanel.set(self.stack.subtract(self.__base)) # Callback method for multiplication button. def __onMulButtonClick(self): self.__iopanel.reset() # Sets the output to the multiplied result. self.__iopanel.set(self.stack.multiply(self.__base)) # Callback method for division button def __onDivButtonClick(self): self.__iopanel.reset() # Sets the output to the divided result. self.__iopanel.set(self.stack.division(self.__base)) # Callback method for unary minus button def __onUMinButtonClick(self): # Creates a new integer which is equal to the negative of the # value of the operand. um = int(self.__iopanel.get()) * -1 # Resets the user inputted value self.__iopanel.reset() # Sets the iopanel input equal to the negative of the given # user inputted value. self.__iopanel.append(str(um))