简体   繁体   中英

Tkinter Binding a keyboard key to a button's command in python

No! Not to a function, but to the button's specified "command" option at any specific moment in the program. I have a code block where the button changes it's function and appearance but I want the Enter key to be bound to it, no matter the function it calls. There are points in the program where the button is disabled, but binding the enter key to it still activates the function, even though the button's disabled. There has to be a way to do that, or a way around it. Maybe there's a way to simulate the button-click event somehow. I just can't believe there's no direct way to do this. The only alternative I see at the moment is to keep binding and unbinding for every function and button. It just seems so un-pythonic.

If your binding calls the invoke method of the button, then it will do nothing when the button is disabled. If the button is enabled, it will do whatever the button is designed to do. Of course, you could also just bind to a function that checks the state of the button before doing anything.

Here's a contrived example. It contains a button labelled "Count" which increments a counter and updates the display. There are two other buttons used to enable or disable this first button.

Once the window has focus, if you press the return key it will invoke the button. Notice that after you disable the button the return key does nothing. When you re-enable the button the return key works again.

示例截图

import tkinter as tk

COUNT = 0

def count():
    global COUNT
    COUNT += 1
    label.configure(text=f"Count: {COUNT}")

root = tk.Tk()

label = tk.Label(root, text="Count: 0")
button = tk.Button(root, text="Count", command=count)
enable_btn = tk.Button(root, text="Enable Count", command=lambda: button.configure(state="normal"))
disable_btn = tk.Button(root, text="Disable Count", command=lambda: button.configure(state="disabled"))

label.pack(side="top", fill="x", pady=20)
button.pack(side="left", padx=(0,10))
disable_btn.pack(side="right")
enable_btn.pack(side="right")

root.bind_all("<Return>", lambda event: button.invoke())

root.mainloop()

A button's command can be invoked as

btn = tkinter.Button(command=lambda: print("Hello!"), text="Press me for greeting")
btn.pack() # This is not required to allow invoke() to work
btn.invoke()

which calls the function. This works even if the button is not actually on-screen, as shown in the snippet.

However, it will not work if the button state is "disabled" . I would recommend storing the function used in a separate variable in this case.

In the example below, the command for the button just calls a method belonging to the class. This means that you can call the function by pressing a button, or by calling the method directly, even if the button is disabled, hidden or deleted. The button simply looks at the current definition of the function and calls it.

import tkinter as tk

class Window(tk.Tk):
    def __init__(self):
        super().__init__()
        self.bind("<Return>", lambda event: self.current_button_function())
        self.btn = tk.Button(self, text="Press me!", command=lambda: self.current_button_function())
        # command=self.current_button_function won't work since it won't update when the function updates
        self.btn.pack()
        self.mainloop()
    
    def current_button_function(self):
        print("This is a function. Button click is now disabled but function is still callable and enter still works")
        self.btn.configure(state="disabled")
        #self.current_button_function = lambda: print("This is simple lambda") # For easily returning single expression
        def tmp(): # For a multi-line function
            print("This is another function which works even though the button is disabled! The button is no longer on the page but the function is still callable and enter still works")
            self.btn.forget()
            def tmp():
                print("The button is not on the page but it doesn't matter!")
                #Could continue adding nested 'def' and/or 'lambda'
            self.current_button_function = tmp
        self.current_button_function = tmp
        
if __name__ == "__main__":
    window = Window()

Try clicking the button and/or pressing enter a few times to see it change the callback function and still work even when the button is forgotten or disabled.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM