Home > OS >  How to bind a key to click a certain button?
How to bind a key to click a certain button?

Time:06-18

I want to know how to make a key bind to click a certain button, I tried using keyboard events but I have no idea how to use it on my calculator program. I tried binding but the only thing it can do is to print something like "you pressed Enter Button", but in my program I have no idea how to write it. I want it if I pressed key "1" then the 1 will be shown to the keyboard monitor. It's okay if you will not bind all the keys I just want to know how to bind a single key and I will do the rest.

from tkinter import *

def button_press(num):
    global equation_text
    equation_text = equation_text   str(num)
    equation_label.set(equation_text)

def equals():
    global equation_text
    try:
        total = str(eval(equation_text))
        equation_label.set(total)
        equation_text = total

    except SyntaxError:
        equation_label.set("syntax error")
        equation_text = ""

    except ZeroDivisionError:
        equation_label.set("arithmetic error")
        equation_text = ""

def clear():
    global equation_text
    equation_label.set("")
    equation_text = ""


window = Tk()
window.title("Calculator - Navarez")
window.geometry("365x500")

equation_text = ""

equation_label = StringVar()

label = Label(window, textvariable=equation_label, font=('consolas',20), fg="white", bg="black", width=24, height=2)
label.pack()

frame = Frame(window)
frame.pack()



button1 = Button(frame, text=1, height=4, width=9, font=35,
                 command=lambda: button_press(1))
button1.grid(row=0, column=0)
#window.bind('<1>', lambda event: button_press(1))

button2 = Button(frame, text=2, height=4, width=9, font=35,
                 command=lambda: button_press(2))
button2.grid(row=0, column=1)

button3 = Button(frame, text=3, height=4, width=9, font=35,
                 command=lambda: button_press(3))
button3.grid(row=0, column=2)

button4 = Button(frame, text=4, height=4, width=9, font=35,
                 command=lambda: button_press(4))
button4.grid(row=1, column=0)

button5 = Button(frame, text=5, height=4, width=9, font=35,
                 command=lambda: button_press(5))
button5.grid(row=1, column=1)

button6 = Button(frame, text=6, height=4, width=9, font=35,
                 command=lambda: button_press(6))
button6.grid(row=1, column=2)

button7 = Button(frame, text=7, height=4, width=9, font=35,
                 command=lambda: button_press(7))
button7.grid(row=2, column=0)

button8 = Button(frame, text=8, height=4, width=9, font=35,
                 command=lambda: button_press(8))
button8.grid(row=2, column=1)

button9 = Button(frame, text=9, height=4, width=9, font=35,
                 command=lambda: button_press(9))
button9.grid(row=2, column=2)

button0 = Button(frame, text=0, height=4, width=9, font=35,
                 command=lambda: button_press(0))
button0.grid(row=3, column=0)

plus = Button(frame, text=' ', height=4, width=9, font=35,
                 command=lambda: button_press(' '))
plus.grid(row=0, column=3)

minus = Button(frame, text='-', height=4, width=9, font=35,
                 command=lambda: button_press('-'))
minus.grid(row=1, column=3)

multiply = Button(frame, text='*', height=4, width=9, font=35,
                 command=lambda: button_press('*'))
multiply.grid(row=2, column=3)

divide = Button(frame, text='/', height=4, width=9, font=35,
                 command=lambda: button_press('/'))
divide.grid(row=3, column=3)

equal = Button(frame, text='=', height=4, width=9, font=35,
                 command=equals)
equal.grid(row=3, column=2)

decimal = Button(frame, text='.', height=4, width=9, font=35,
                 command=lambda: button_press('.'))
decimal.grid(row=3, column=1)

clear = Button(window, text='C', height=4, width=12,font=35,
                 command=clear)

clear.pack()

window.mainloop()

CodePudding user response:

Maybe you could use

window.bind('1', lambda event: button_press(1))

just change the 1 to any other number

i dont know if this would work because im really new to python

so it would look like this

from tkinter import *

def button_press(num):
    global equation_text
    equation_text = equation_text   str(num)
    equation_label.set(equation_text)

def equals():
    global equation_text
    try:
        total = str(eval(equation_text))
        equation_label.set(total)
        equation_text = total

    except SyntaxError:
        equation_label.set("syntax error")
        equation_text = ""

    except ZeroDivisionError:
        equation_label.set("arithmetic error")
        equation_text = ""

def clear():
    global equation_text
    equation_label.set("")
    equation_text = ""


window = Tk()
window.title("Calculator - Navarez")
window.geometry("365x500")

window.bind('1', lambda event: button_press(1))
window.bind('2', lambda event: button_press(2))
window.bind('3', lambda event: button_press(3))
window.bind('4', lambda event: button_press(4))
window.bind('5', lambda event: button_press(5))
window.bind('6', lambda event: button_press(6))
window.bind('7', lambda event: button_press(7))
window.bind('8', lambda event: button_press(8))
window.bind('9', lambda event: button_press(9))
window.bind('0', lambda event: button_press(0))
window.bind('.', lambda event: button_press('.'))
window.bind('=', lambda event: equals())
window.bind('/', lambda event: button_press('/'))
window.bind(' ', lambda event: button_press(' '))
window.bind('-', lambda event: button_press('-'))
window.bind('*', lambda event: button_press('*'))


equation_text = ""

equation_label = StringVar()

label = Label(window, textvariable=equation_label, font=('consolas',20), fg="white", bg="black", width=24, height=2)
label.pack()

frame = Frame(window)
frame.pack()



button1 = Button(frame, text=1, height=4, width=9, font=35,
                 command=lambda: button_press(1))
button1.grid(row=0, column=0)
#window.bind('<1>', lambda event: button_press(1))

button2 = Button(frame, text=2, height=4, width=9, font=35,
                 command=lambda: button_press(2))
button2.grid(row=0, column=1)

button3 = Button(frame, text=3, height=4, width=9, font=35,
                 command=lambda: button_press(3))
button3.grid(row=0, column=2)

button4 = Button(frame, text=4, height=4, width=9, font=35,
                 command=lambda: button_press(4))
button4.grid(row=1, column=0)

button5 = Button(frame, text=5, height=4, width=9, font=35,
                 command=lambda: button_press(5))
button5.grid(row=1, column=1)

button6 = Button(frame, text=6, height=4, width=9, font=35,
                 command=lambda: button_press(6))
button6.grid(row=1, column=2)

button7 = Button(frame, text=7, height=4, width=9, font=35,
                 command=lambda: button_press(7))
button7.grid(row=2, column=0)

button8 = Button(frame, text=8, height=4, width=9, font=35,
                 command=lambda: button_press(8))
button8.grid(row=2, column=1)

button9 = Button(frame, text=9, height=4, width=9, font=35,
                 command=lambda: button_press(9))
button9.grid(row=2, column=2)

button0 = Button(frame, text=0, height=4, width=9, font=35,
                 command=lambda: button_press(0))
button0.grid(row=3, column=0)

plus = Button(frame, text=' ', height=4, width=9, font=35,
                 command=lambda: button_press(' '))
plus.grid(row=0, column=3)

minus = Button(frame, text='-', height=4, width=9, font=35,
                 command=lambda: button_press('-'))
minus.grid(row=1, column=3)

multiply = Button(frame, text='*', height=4, width=9, font=35,
                 command=lambda: button_press('*'))
multiply.grid(row=2, column=3)

divide = Button(frame, text='/', height=4, width=9, font=35,
                 command=lambda: button_press('/'))
divide.grid(row=3, column=3)

equal = Button(frame, text='=', height=4, width=9, font=35,
                 command=equals)
equal.grid(row=3, column=2)

decimal = Button(frame, text='.', height=4, width=9, font=35,
                 command=lambda: button_press('.'))
decimal.grid(row=3, column=1)

clear = Button(window, text='C', height=4, width=12,font=35,
                 command=clear)

clear.pack()

window.mainloop()

CodePudding user response:

Processing of keypresses in tkinter is really very straightforward. Only one short command window.bind("<Key>" , on_single_key) with appropriate def on_single_key(e): function processing presses of keyboard keys:

from tkinter import Tk, StringVar, Label, Frame, Button

# [... all your code ... ]

window.geometry("640x715") # looks best on my screen

def on_single_key(e): 
    strKey = e.char
    if strKey == "":
        return
    if strKey in '0123456789':
        button_press(int(strKey))        
    if strKey in ' -*/.':
        button_press(strKey)
    if strKey in 'Cc':
        clear_input()        
    if strKey == '=' or strKey == '\r':
        equals()        
#:def on_single_key(e)               
window.bind("<Key>" , on_single_key)

window.mainloop()

The code above covers all the clickable buttons and uses the feature of strings making it possible to use them in a same way as a list of characters.

Also the other calculator code can take advantage of lists and strings. This reduces the amount of code. For the sake of completeness here the entire calculator code generating its buttons from a list looping over rows and columns of the grid the buttons are placed into:

# https://stackoverflow.com/questions/72665537/how-to-bind-a-key-to-click-a-certain-button
from tkinter import Tk, StringVar, Label, Frame, Button
def button_press(char):
    global equation_text
    if char in '123 456-789*0./':  
        equation_text  = char
        equation_label.set(equation_text)
    elif char in "=\r":  equals()
    elif char in 'cC' :  clear_input()        
def equals():
    global equation_text
    try:
        total = str(eval(equation_text))
        equation_label.set(total)
        equation_text = total
    except SyntaxError:
        equation_label.set("syntax error")
        equation_text = ""
    except ZeroDivisionError:
        equation_label.set("arithmetic error")
        equation_text = ""
def clear_input():
    global equation_text
    equation_label.set("")
    equation_text = ""

window = Tk()
window.title("Calculator - Navarez")
window.geometry("640x715")

equation_text = ""
equation_label = StringVar()

label = Label(window, textvariable=equation_label, font=('consolas',20), 
              fg="white", bg="black", width=24, height=2)
label.pack(pady=15)

frame = Frame(window)
frame.pack()

lstButtonText = ["123 ","456-","789*","0.=/",]
for row in range(0,4):
    for column in range(0,4):
        char = lstButtonText[row][column]
        Button(frame, text=char, height=4, width=9, font=35, 
               command=lambda char=char: button_press(char)).grid(
                   row=row, column=column)
Button(window, text='C', height=4, width=12,font=35,
       command=clear_input).pack()

def on_single_key(e): 
    strKey = e.char
    if strKey and strKey in '123 456-789*0.=/\rcC':
        button_press(strKey)
#:def on_single_key(e)
window.bind("<Key>", on_single_key)
window.mainloop()

The part command=lambda char=char: button_press(char) of the loop over rows and columns is a bit tricky and not easy to understand for a beginner. char=char sets the default value for the parameter of a function which is the value at the time of function definition with lambda. This guarantees passing of the right parameter to the button_press(char) command function of the button.

Finally next to usage of lists and strings the event callback function can be unified handling both, buttons and keyboard. This reduces the calculator code to:

from tkinter import Tk, StringVar, Label, Frame, Button
root = Tk();root.title("Calculator - Navarez");root.geometry("640x715")
lcd_text = ""; lcd_label = StringVar()
Label(root, textvariable=lcd_label, font=('consolas',20), 
      fg="white", bg="black", width=24, height=2).pack(pady=15)
frame = Frame(root); frame.pack()
lstButtonText = ["123 ","456-","789*","0.=/",]
for row in range(0,4):
    for column in range(0,4):
        char = lstButtonText[row][column]
        Button(frame, text=char, height=4, width=9, font=35, 
               command=lambda char=char: on_user_action(char)).grid(
                   row=row, column=column)
Button(root, text='C', height=4, width=12,font=35,
       command=lambda: on_user_action('C')).pack()
def on_user_action(e): 
    global lcd_text
    char = e.char if type(e) != str else e 
    if char and char in '123 456-789*0.=/\rcC': 
        # in Python bool("") is False so empty strings are rejected
        if char in '123 456-789*0./':  
            lcd_text  = char    ; lcd_label.set(lcd_text)
        elif char in "=\r":  
            try: 
                total = str(eval(lcd_text))
                lcd_text = total; lcd_label.set(total)          ; 
            except SyntaxError:
                lcd_text = ""   ; lcd_label.set("Error (Syntax Error)") 
            except ZeroDivisionError:
                lcd_text = ""   ; lcd_label.set("Error (ZeroDivision)")
        elif char in 'cC' :  
            lcd_text = ""       ; lcd_label.set("")
#:def on_user_action(e)
root.bind("<Key>", on_user_action)
root.mainloop()

By the way: tkinter supports next to a single press of a keyboard key also events of double and even triple presses of a keyboard key. This works like a double click of a mouse button and is available for all keys on a keyboard. It has sure the potential of a very powerful and interesting way to interact with a user, but to my knowledge it stays dormant and unknown.

  • Related