A calculator with tkinter
We are going to make another example with tkinter, building an app to create a calculator. Let’s start analysing each widget in the window.
The display (Entry widget)
To make the display we are going to use the following code:
######################## #### the display ##### ######################## display = tk.StringVar() # relief can be FLAT or RIDGE or RAISED or SUNKEN GROOVE entry_display = tk.Entry(self) entry_display['relief'] = tk.FLAT entry_display['textvariable'] = display entry_display['justify'] = 'right' entry_display['bd'] = 30 entry_display['bg'] = 'orange' entry_display.pack(side=tk.TOP, expand=tk.YES, fill=tk.BOTH)
Let’s comment the code
# THE VARIABLE TO GET THE VALUE IN THE DISPLAY display = tk.StringVar() # THE ENTRY OBJECT = DISPLAY entry_display = tk.Entry(self) # THE BORDER = FLAT entry_display['relief'] = tk.FLAT # IT CAN BE FLAT or RIDGE or RAISED or SUNKEN GROOVE # THE VARIABLE SEEN BEFOR entry_display['textvariable'] = display # JUSTIFICATED TO THE RIGHT entry_display['justify'] = 'right' # THE THIKNESS entry_display['bd'] = 30 # THE BACKGROUND COLOR entry_display['bg'] = 'orange' # TO SEE IT, AT THE TOP, EXTENDED AS LONG AS THE WINDOW entry_display.pack(side=tk.TOP, expand=tk.YES, fill=tk.BOTH)
The whole code
from tkinter import * #This function returns a Frame def iCalc(source, side): "Returns a Frame object yet packed and expanded, to shorten the code" # the bd is the border of the frame storeObj = Frame(source, borderwidth=10, bd=1, bg="gray") # the pack methos is needed to diplay the object storeObj.pack(side=side, expand=YES, fill=BOTH) return storeObj def button(source, side, text, command=None): "Return a Button object that is packed yet" storeObj = Button(source, text=text, command=command) storeObj.pack(side=side, expand=YES, fill=BOTH) return storeObj # This class inherit from Frame class App(Frame): def __init__(self): Frame.__init__(self) self.option_add("*Font", "arial 20 bold") self.pack(expand=YES, fill=BOTH) self.master.title("Calculator") # THE DISPLAY display = StringVar() # relief can be FLAT or RIDGE or RAISED or SUNKEN GROOVE entry = Entry(self, relief=FLAT, textvariable=display, justify='right', bd=15, bg='orange') entry.pack(side=TOP) # I added an action to calculate the operation when Return (Enter) is hit entry.focus() # You can hit enter to get the result instead of clicking = self.master.bind("<Return>", lambda e, s=self, storeObj=display: s.calc(storeObj)) # YOu can click del button on the keyboard to cancel self.master.bind("<Delete>", lambda e, s=self, storeObj=display: storeObj.set("")) self.master.bind("<BackSpace>", lambda e, s=self, storeObj=display: storeObj.set("")) # Thi is the frame for the [C] button erase = iCalc(self, TOP) clearBut = "C" button(erase, LEFT, clearBut, lambda storeObj=display, q=clearBut: storeObj.set("")) for numBut in ("789/", "456*", "123-", "0.+"): functionNum = iCalc(self, TOP) for char in numBut: button(functionNum, LEFT, char, lambda storeObj=display, q=char: storeObj.set(storeObj.get() + q)) equalButton = iCalc(self, TOP) for iEqual in "=": if iEqual == "=": btniEqual = button(equalButton, LEFT, iEqual) btniEqual.bind("<ButtonRelease-1>", lambda e, s=self, storeObj=display: s.calc(storeObj), '+') else: btniEqual = button(equalButton, LEFT, iEqual, lambda storeObj=display, s='%s' % iEqual: storeObj.set(storeObj.get() + s)) def calc(self, display): try: # Sets the display to the evaluation of the string in the display itself, i.e. calculate the result display.set(eval(display.get())) except: # if something goes wrong with the result display.set("ERROR") if __name__ == '__main__': App().mainloop()
Video to show the app running
Version 2
In this version we have a different look, with a very big delete button.
from tkinter import * #This function returns a Frame def iCalc(source, side): "Returns a Frame object yet packed and expanded, to shorten the code" # the bd is the border of the frame storeObj = Frame(source, borderwidth=10, bd=1, bg="gray") # the pack methos is needed to diplay the object storeObj.pack(side=side, expand=YES, fill=BOTH) return storeObj def button(source, side, text, command=None): "Return a Button object that is packed yet" storeObj = Button(source, text=text, command=command) storeObj.pack(side=side, expand=YES, fill=BOTH) return storeObj # This class inherit from Frame class App(Frame): def __init__(self): Frame.__init__(self) self.option_add("*Font", "arial 20 bold") self.pack(expand=YES, fill=BOTH) self.master.title("Calculator") # THE DISPLAY display = StringVar() # relief can be FLAT or RIDGE or RAISED or SUNKEN GROOVE entry = Entry(self, relief=FLAT, textvariable=display, justify='right', bd=15, bg='orange') entry.pack(side=TOP) # I added an action to calculate the operation when Return (Enter) is hit entry.focus() # You can hit enter to get the result instead of clicking = self.master.bind("<Return>", lambda e, s=self, storeObj=display: s.calc(storeObj)) # YOu can click del button on the keyboard to cancel self.master.bind("<Delete>", lambda e, s=self, storeObj=display: storeObj.set("")) self.master.bind("<BackSpace>", lambda e, s=self, storeObj=display: storeObj.set("")) # Thi is the frame for the [C] button erase = iCalc(self, LEFT) clearBut = "Delete" button(erase, LEFT, clearBut, lambda storeObj=display, q=clearBut: storeObj.set("")) for numBut in ("789/", "456*", "123-", "0.+"): functionNum = iCalc(self, TOP) for char in numBut: button(functionNum, LEFT, char, lambda storeObj=display, q=char: storeObj.set(storeObj.get() + q)) equalButton = iCalc(self, TOP) for iEqual in "=": if iEqual == "=": btniEqual = button(equalButton, LEFT, iEqual) btniEqual.bind("<ButtonRelease-1>", lambda e, s=self, storeObj=display: s.calc(storeObj), '+') else: btniEqual = button(equalButton, LEFT, iEqual, lambda storeObj=display, s='%s' % iEqual: storeObj.set(storeObj.get() + s)) def calc(self, display): try: # Sets the display to the evaluation of the string in the display itself, i.e. calculate the result display.set(eval(display.get())) except: # if something goes wrong with the result display.set("ERROR") if __name__ == '__main__': App().mainloop()
Minimal layout: Mini-Calculator
The article with the mini-calculator code (another version, minimal).