1

I have recently designed a simple GUI calculator using Tkinter in Python. I have created the buttons using button widgets, and obviously you use your mouse to click the buttons to enter the expressions and click the equal button to get the answer. However, what I want to do now is to implement the calculator such that I can press the keys on my computer's keyboard to enter the expression and, for example, press the equals button on my computer's keyboard instead of having to click the buttons on the GUI using my mouse.

How do I go about doing this?

I have tried the 'bind' function, but it returns an attribute error saying: AttributeError: 'NoneType' object has no attribute 'bind'. I have searched various way on how to correct this, but nothing seems to work.

Is it possible to fix this error (and if so how) or is there another way to do it?

Here's my code:

# Python program to  create a simple GUI Calculator using Tkinter


# Part 1
# import from tkinter - Part 1
from tkinter import*


#Part 2
# Function to update expression in the text entry box
def buttonClick(numbers):
    global operator # global expression variable
    operator = operator + str(numbers)  # string concatenation
    text_Input.set(operator) # Use set method to update the expression

# Function to clear contents
# of the text entry box
def buttonClearDisplay():
    global operator

    operator = ""
    text_Input.set("")

def buttonEqualsInput():
    # I used a try and except statement
    # for handling the zero
    # division error

    try:
        global operator

        # eval function evaluates the 'expression'
        # and str function converts the result
        # into a string

        answer = str(eval(operator))
        text_Input.set(answer)

        # initializes the expression variable
        # to an empty string
        operator = ""

    except:
        # if an error is generated then handle
        # using the except block
        text_Input.set("error")
        operator = ""


# Part 3
# 3.1- create a GUI window - make window with name 'cal' - set it to the Tkinter GUI window Tk()
# use function properties to set various properties of the GUI
cal = Tk() # instantiate
cal.title("Calculator") # set title of GUI window
operator = ""

# StringVar() is the variable class
# Create an instance of this class
# used to display the numbers and operands
text_Input = StringVar()

# 3.2 TextDisplay - for creating the text entry box showing the numbers/expressions.
textDisplay = Entry(cal, font = ('Times New Roman', 20, 'bold'), textvariable = text_Input, bd = 30, insertwidth = 4,
                   bg = "powder blue", justify = 'right').grid(columnspan = 4)

# 3.3 - create Buttons and place at a particular
# locations inside the window.
# When user presses button, the command or
# function affiliated to that button is executed.
# Properties such as text, background colour, width & height etc can be edited.
# Use command - lambda to give buttons functionality.
# Use grid to place buttons at a particular position in the window.

#Row 1
button7 = Button(cal, padx = 16, pady = 16, bd = 8, fg = "black", font = ('arial', 20, 'bold'), text = "7",
              command = lambda:buttonClick(7)).grid(row = 1, column = 0)


button8 = Button(cal, padx = 16, pady = 16, bd = 8, fg = "black", font = ('arial', 20, 'bold'), text = "8",
              command = lambda:buttonClick(8)).grid(row = 1, column = 1)
button9 = Button(cal, padx = 16, pady = 16, bd = 8, fg = "black", font = ('arial', 20, 'bold'), text = "9",
              command = lambda:buttonClick(9)).grid(row = 1, column = 2)
Addition = Button(cal, padx = 16, pady = 16, bd = 8, fg = "black", font = ('arial', 20, 'bold'), text = "+",
                  command = lambda:buttonClick("+")).grid(row = 1, column = 3)

#========================================================================================================================

#Row 2

button4 = Button(cal, padx = 16, pady = 16, bd = 8, fg = "black", font = ('arial', 20, 'bold'), text = "4",
              command = lambda:buttonClick(4)).grid(row = 2, column = 0)
button5 = Button(cal, padx = 16, pady = 16, bd = 8, fg = "black", font = ('arial', 20, 'bold'), text = "5",
              command = lambda:buttonClick(5)).grid(row = 2, column = 1)
button6 = Button(cal, padx = 16, pady = 16, bd = 8, fg = "black", font = ('arial', 20, 'bold'), text = "6",
              command = lambda:buttonClick(6)).grid(row = 2, column = 2)
Subtraction = Button(cal, padx = 16, pady = 16, bd = 8, fg = "black", font = ('arial', 20, 'bold'), text = "-",
                     command = lambda:buttonClick("-")).grid(row = 2, column = 3)

#========================================================================================================================

#Row 3

button1 = Button(cal, padx = 16, pady = 16, bd = 8, fg = "black", font = ('arial', 20, 'bold'), text = "1",
              command = lambda:buttonClick(1)).grid(row = 3, column = 0)
button2 = Button(cal, padx = 16, pady = 16, bd = 8, fg = "black", font = ('arial', 20, 'bold'), text = "2",
              command = lambda:buttonClick(2)).grid(row = 3, column = 1)
button3 = Button(cal, padx = 16, pady = 16, bd = 8, fg = "black", font = ('arial', 20, 'bold'), text = "3",
              command = lambda:buttonClick(3)).grid(row = 3, column = 2)
Multiplication = Button(cal, padx = 16, pady = 16, bd = 8, fg = "black", font = ('arial', 20, 'bold'), text = "*",
                        command = lambda:buttonClick("*")).grid(row = 3, column = 3)

#========================================================================================================================

#Row 4

button0 = Button(cal, padx = 16, pady = 16, bd = 8, fg = "black", font = ('arial', 20, 'bold'), text = "0",
              command = lambda:buttonClick(0)).grid(row = 4, column = 0)
buttonClear = Button(cal, padx = 16, pady = 16, bd = 8, fg = "black", font = ('arial', 20, 'bold'), text = "CE",
                  command = buttonClearDisplay).grid(row = 4, column = 1)
buttonEqual = Button(cal, padx = 16, pady = 16, bd = 8, fg = "black", font = ('arial', 20, 'bold'),
                  text = "=", command = buttonEqualsInput).grid(row = 4, column = 2)
Division = Button(cal, padx = 16, pady = 16, bd = 8, fg = "black", font = ('arial', 20, 'bold'), text = "/",
                  command = lambda:buttonClick("/")).grid(row = 4, column = 3)

#========================================================================================================================

#Row 5

Decimal= Button(cal, padx = 16, pady = 16, bd = 8, fg = "black", font = ('arial', 20, 'bold'), text = ".",
                  command = lambda:buttonClick(".")).grid(row = 5, column = 0)
Dummy1= Button(cal, padx = 16, pady = 16, bd = 8, fg = "black", font = ('arial', 20, 'bold'), text = "PY").grid(row = 5, column = 1)
Dummy2= Button(cal, padx = 16, pady = 16, bd = 8, fg = "black", font = ('arial', 20, 'bold'), text = "TH").grid(row = 5, column = 2)
Dummy3= Button(cal, padx = 16, pady = 16, bd = 8, fg = "black", font = ('arial', 20, 'bold'), text = "ON").grid(row = 5, column = 3)




#Start GUI
cal.mainloop()


I have tried for example:

button7.bind("<Button7>", lambda:buttonClick)
 

but this doesn't work

Yash
  • 21
  • 2
  • This will help you to solve the AttributeError: https://stackoverflow.com/questions/1101750/tkinter-attributeerror-nonetype-object-has-no-attribute-attribute-name – j_4321 Jan 13 '21 at 16:56

2 Answers2

1

Don't invoke the Button, just run the same function that the Button does. Like this:

cal.bind("7", lambda e:buttonClick(7))
Novel
  • 13,406
  • 2
  • 25
  • 41
0

Thanks to everyone that responded, I have figured it out.

So, as Novel has just said, don't invoke the button, declare it from the GUI window itself. So whatever the variable is that you set equal to Tk(), you use that variable to do it.

In my case, it is cal = Tk(), so we use the variable 'cal'

the code looks like this:

cal.bind("1", lambda e:buttonClick(1))
cal.bind("2", lambda e:buttonClick(2))
cal.bind("3", lambda e:buttonClick(3))
cal.bind("4", lambda e:buttonClick(4))
cal.bind("5", lambda e:buttonClick(5))
cal.bind("6", lambda e:buttonClick(6))
cal.bind("7", lambda e:buttonClick(7))
cal.bind("8", lambda e:buttonClick(8))
cal.bind("9", lambda e:buttonClick(9))
cal.bind("0", lambda e:buttonClick(0))
cal.bind("<+>", lambda e:buttonClick("+"))
cal.bind("-", lambda e:buttonClick("-"))
cal.bind("<*>", lambda e:buttonClick("*"))
cal.bind("/", lambda e:buttonClick("/"))
cal.bind("c", lambda e:buttonClearDisplay())
cal.bind("=", lambda e:buttonEqualsInput())

Note that any operators inside the arrow brackets indicate to hold shift and that button, so for example '+' on a keyboard needs to be pressed by 'shift and =' to get the plus on a keyboard, any button that does not require the shift key press does not need to be inside arrow brackets. Also make sure that the functions are allocated correctly with the right syntax as shown here.

Yash
  • 21
  • 2