Hi!
I am creating a simple python tkinter calculator. However when I was due to submit my code in my teacher said that my code is inefficient and recommended i change the following:

1.) Create buttons using a for loop
2.) have two classes - one of which is for the functions defintions and one for the GUI components and all
3.) remove all global variables and use parameters and scopes
However i am a novice at programming as i just started recently an have been given a short time. Can anyone help me? Any help is appreciated.

from tkinter import *
from tkinter import messagebox

window = Tk()
window.geometry("314x388") # size of the window 
window.resizable(0, 0) # this prevents from resizing the window
window.title("Python Calculator")

def btn_memory_add():
     global operation
     if(operation != ''):  # if the operation isn't empty (nothing on the screen)
        Mem_ADD = memory_text.get()  # the value of your memory display (top display)
        ans = eval(Mem_ADD + '+' + operation)  # solve the Mem_ADD plus the value on the main display
        memory_text.set(ans)  # set the memory display as the answer
        input_text.set('')  # clear the main display
        operation = ''  # clear the value of the operation

def btn_memory_sub():
     global operation
     if(operation != ''):  # if the operation isn't empty (nothing on the screen)
        Mem_Sub = memory_text.get()# the value of your memory display (top display)
        ans = eval(Mem_Sub + '-' + operation)# solve the Mem_Sub minus the value on the main display
        memory_text.set(ans)# set the memory display as the answer
        input_text.set('') # clear the main display
        operation = ''# clear the value of the operation

def memory_call():
     global operation
     memory = memory_text.get()#gets the value stored in the memory display
     input_text.set(memory)# sets it to the main display
     memory_text.set("")#clears the memory_text once the memory value is displayed in the main area

def memory_clear():
     global operation
     memory_text.set("")

def btn_eval(number):
    global operation
    operation = operation + str(number)
    input_text.set(operation)#set the mathematical operation as the answer
    if (len(operation)) > 24:
        messagebox.showerror("Error Window", "Inputs too Long")
    else:
     return operation

def btn_del():
    global operation
    operation = operation[0:len(operation)-1]#this btn_deletes the last number displayed on screen
    input_text.set(operation)
    operation = operation

def btn_clear():
    global operation 
    operation = "" #clears the value of the operation
    input_text.set("")#clears the display

def btn_equal():
    global operation
    try:
        result = str(eval(operation))# eval function evalutes the string operation directly
        input_text.set(result)
    except ZeroDivisionError:# if zero dividon error arise 
        result = "Zero Division Error"#inform the user about the zero divison error
        input_text.set(result)
    operation = result#allow the user to continuously operate once the results are given
    if (len(result) > 10 ):
        result = "{:e}" .format(float(result))#make a scientific notation once the results length is greater than 10
        input_text.set(result)
    elif (len(result)) > 24:
        messagebox.showerror("Error Window", "Results too Long. Press Clear")#imports message box to show the results is too long
    else:
        return result#if there is no errors than return the result

operation = ""
# 'StringVar()' is used to get the instance of the display area 
input_text = StringVar()
memory_text = StringVar()
# creating a frame for the display area
display_frame = Frame(window, width = 312, height = 50, bd = 0, highlightbackground = "black", highlightcolor = "black", highlightthickness = 1)
display_frame.pack(side = TOP)

# creating a display area inside the display frame
display = Entry(display_frame, font = ('arial', 18, 'bold'), textvariable = memory_text, width = 24, bg = "#eee", bd = 0, justify = RIGHT, state = DISABLED)
display.grid(row = 0, column = 0)
#display.pack(ipady = 10)#internal padding to increase the height of the display area
memory_display = Entry(display_frame, font = ('arial', 18, 'bold'), textvariable = input_text, width = 24, bg = "#eee", bd = 0, justify = RIGHT,  state = DISABLED )
memory_display.grid(row = 1, column = 0)

# creating another frame for the button below the display_frame
btns_frame = Frame(window, width = 312, height = 312, bg = "grey")
btns_frame.pack()

#first row that consists of all the memory buttons
memory_add = Button(btns_frame, text = "M+", fg = "black",  width = 10, height = 3, bd = 0, bg = "#fff", cursor = "hand2",activebackground = "#1E90FF", command = lambda: btn_memory_add())
memory_add.grid(row = 0, column = 0,  padx = 1, pady = 1)
window.bind('a', lambda event: btn_memory_add()) #the letter "a" represents M+ button on the keyboard
memory_subtract = Button(btns_frame, text = "M-", fg = "black",  width = 10, height = 3, bd = 0, bg = "#fff", cursor = "hand2",activebackground = "#1E90FF", command = lambda: btn_memory_sub())
memory_subtract.grid(row = 0, column = 1, padx = 1, pady = 1)
window.bind('s', lambda event: btn_memory_sub())#the letter "s" represents M- button on the keyboard
memory_recall = Button(btns_frame, text = "MR", fg = "black",  width = 10, height = 3, bd = 0, bg = "#fff", cursor = "hand2",activebackground = "#1E90FF", command = lambda: memory_call())
memory_recall.grid(row = 0, column = 2, padx = 1, pady = 1)
window.bind('r', lambda event: memory_call())#the letter "r" represents MR button on the keyboard
memory_btn_clear = Button(btns_frame, text = "MC", fg = "black",  width = 10, height = 3, bd = 0, bg = "#fff", cursor = "hand2", activebackground = "#1E90FF", command = lambda: memory_clear())
memory_btn_clear.grid(row = 0, column = 3, padx = 1, pady = 1)
window.bind('m', lambda event: memory_clear())#the letter "m" represents MC button on the keyboard

 #second row that consists of the clear , delete and divide button
clear = Button(btns_frame, text = "C", fg = "black", width = 21, height = 3, bd = 0, bg = "#fff", cursor = "hand2",activebackground = "#1E90FF" ,command = lambda: btn_clear())
clear.grid(row = 1, column = 0,columnspan = 2, padx = 1, pady = 1)
window.bind('c', lambda event: btn_clear())#the letter "a" represents the clear button on the keyboard
btn_delete = Button(btns_frame, text = "Del", fg = "black", width = 10, height = 3, bd = 0, bg = "#fff", cursor = "hand2",activebackground = "#1E90FF", command = lambda: btn_del())
btn_delete.grid(row = 1, column = 2, padx = 1, pady = 1)
window.bind('<BackSpace>', lambda event: btn_del())#the backspace represents the DEL button on the keyboard
btn_divide = Button(btns_frame, text = "/", fg = "black", width = 10, height = 3, bd = 0, bg = "#fff", cursor = "hand2",activebackground = "#1E90FF", command = lambda: btn_eval("/"))
btn_divide.grid(row = 1, column = 3, padx = 1, pady = 1)
window.bind('/', lambda event: btn_eval('/'))#the stroke buttons represent the division button

# third row consists of the number 7 , 8 , 9 and multiplication button
btn_seven = Button(btns_frame, text = "7", fg = "black", width = 10, height = 3, bd = 0, bg = "#fff", cursor = "hand2",activebackground = "#1E90FF", command = lambda: btn_eval(7))
btn_seven.grid(row = 2, column = 0, padx = 1, pady = 1)
window.bind('7', lambda event: btn_eval(7))
btn_eight = Button(btns_frame, text = "8", fg = "black", width = 10, height = 3, bd = 0, bg = "#fff", cursor = "hand2",activebackground = "#1E90FF",command = lambda: btn_eval(8))
btn_eight.grid(row = 2, column = 1, padx = 1, pady = 1)
window.bind('8', lambda event: btn_eval(8))
btn_nine = Button(btns_frame, text = "9", fg = "black", width = 10, height = 3, bd = 0, bg = "#fff", cursor = "hand2",activebackground = "#1E90FF", command = lambda: btn_eval(9))
btn_nine.grid(row = 2, column = 2, padx = 1, pady = 1)
window.bind('9', lambda event: btn_eval(9))
btn_multiply = Button(btns_frame, text = "*", fg = "black", width = 10, height = 3, bd = 0, bg = "#fff", cursor = "hand2",activebackground = "#1E90FF", command = lambda: btn_eval("*"))
btn_multiply.grid(row = 2, column = 3, padx = 1, pady = 1)
window.bind('*', lambda event: btn_eval('*'))

# fourth row consists of the number 4, 5 , 6 and minus buttons
btn_four = Button(btns_frame, text = "4", fg = "black", width = 10, height = 3, bd = 0, bg = "#fff", cursor = "hand2",activebackground = "#1E90FF", command = lambda: btn_eval(4))
btn_four.grid(row = 3, column = 0, padx = 1, pady = 1)
window.bind('4', lambda event: btn_eval(4))
btn_five = Button(btns_frame, text = "5", fg = "black", width = 10, height = 3, bd = 0, bg = "#fff", cursor = "hand2",activebackground = "#1E90FF", command = lambda: btn_eval(5))
btn_five.grid(row = 3, column = 1, padx = 1, pady = 1)
window.bind('5', lambda event: btn_eval(5))
btn_six = Button(btns_frame, text = "6", fg = "black", width = 10, height = 3, bd = 0, bg = "#fff", cursor = "hand2",activebackground = "#1E90FF", command = lambda: btn_eval(6))
btn_six.grid(row = 3, column = 2, padx = 1, pady = 1)
window.bind('6', lambda event: btn_eval(6))
btn_minus = Button(btns_frame, text = "-", fg = "black", width = 10, height = 3, bd = 0, bg = "#fff", cursor = "hand2",activebackground = "#1E90FF", command = lambda: btn_eval("-"))
btn_minus.grid(row = 3, column = 3, padx = 1, pady = 1)
window.bind('-', lambda event: btn_eval('-'))

# fifth row consists of one, two , three and plus button
btn_one = Button(btns_frame, text = "1", fg = "black", width = 10, height = 3, bd = 0, bg = "#fff", cursor = "hand2",activebackground = "#1E90FF", command = lambda: btn_eval(1))
btn_one.grid(row = 4, column = 0, padx = 1, pady = 1)
window.bind('1', lambda event: btn_eval(1))
btn_two= Button(btns_frame, text = "2", fg = "black", width = 10, height = 3, bd = 0, bg = "#fff", cursor = "hand2",activebackground = "#1E90FF", command = lambda: btn_eval(2))
btn_two.grid(row = 4, column = 1, padx = 1, pady = 1)
window.bind('2', lambda event: btn_eval(2))
btn_three = Button(btns_frame, text = "3", fg = "black", width = 10, height = 3, bd = 0, bg = "#fff", cursor = "hand2",activebackground = "#1E90FF", command = lambda: btn_eval(3))
btn_three.grid(row = 4, column = 2, padx = 1, pady = 1)
window.bind('3', lambda event: btn_eval(3))
plus = Button(btns_frame, text = "+", fg = "black", width = 10, height = 3, bd = 0, bg = "#fff", cursor = "hand2",activebackground = "#1E90FF", command = lambda: btn_eval("+"))
plus.grid(row = 4, column = 3, padx = 1, pady = 1)
window.bind('+', lambda event: btn_eval("+"))

#sixth row zero, decimal point and equals button
zero = Button(btns_frame, text = "0", fg = "black", width = 21, height = 3, bd = 0, bg = "#fff", cursor = "hand2",activebackground = "#1E90FF", command = lambda: btn_eval(0))
zero.grid(row = 5, column = 0, columnspan = 2, padx = 1, pady = 1)
window.bind('0', lambda event: btn_eval(0))
point = Button(btns_frame, text = ".", fg = "black", width = 10, height = 3, bd = 0, bg = "#fff", cursor = "hand2",activebackground = "#1E90FF", command = lambda: btn_eval("."))
point.grid(row = 5, column = 2, padx = 1, pady = 1)
window.bind('.', lambda event: btn_eval('.'))
equals = Button(btns_frame, text = "=", fg = "black", width = 10, height = 3, bd = 0, bg = "#fff", cursor = "hand2",activebackground = "#1E90FF", command = lambda: btn_equal())
equals.grid(row = 5, column = 3, padx = 1, pady = 1)
window.bind('=', lambda event: btn_equal())

window.mainloop()

Recommended Answers

All 2 Replies

Can anyone help me?

Not without knowing what you have tried.

The number buttons is a simple for loop

this_row = 2
this_col=0
for num in [7, 8, 9, "*", 4, 5, 6, "-", 1, 2, 3, "+"]:
    Button(btns_frame, text = num, fg = "black", width = 10, height = 3, bd = 0,
               bg = "#fff", cursor = "hand2",activebackground = "#1E90FF", 
               command = lambda: btn_eval(num)).grid(row = this_row,
               column = this_column, padx = 1, pady = 1)
    this_col += 1
    if this_col > 3:
        this_row += 1
        this_col = 0

Your teacher is right. If you see lots of lines in the code, that differ from each other only in a few characters, then your code (or your programming language) is inefficient.
Please remove globals. They render the code very hard to read. If you use "import * " then you should prefix(eg bind to a class) all local variables. See this in examples.

There are several good examples of python tkinter calculators on the net. On this page you can see a code several buttons created with only one line containing "Button".

Another good example is here

You should be able to write a calculator with four operation and memory under 200 easily. For the first glance this can get easily shortened with a button dictionary.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.