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).
Tkinter test for students
Tkinter articles
