Binding <Return> to button is not working as expected

16,531

Your code looks fine, but note that the focus must be on the button if you want Return to call self.search(). You can change the focus from widget to widget by pressing Tab. The widget in focus is outlined with a thin black line. You may have to press Tab one or more times to move the focus to the button before pressing Return.

If you want Return to work anywhere in the GUI window, then change

self.button1.bind('<Return>', self.search)

to

root.bind('<Return>', self.search)

where root = tk.Tk().

For example, compare button.bind with master.bind in the code below:

import Tkinter as tk

class SimpleApp(object):
    def __init__(self, master, **kwargs):
        title = kwargs.pop('title')
        frame = tk.Frame(master, **kwargs)
        frame.grid()
        button = tk.Button(frame, text = 'search', command = self.search)
        button.grid()
        button.bind('<Return>', self.search)
        # uncomment if you want `<Return>` bound everywhere.
        # master.bind('<Return>', self.search)  
    def search(self,*args):
        print('searching...')

def basic():
    root = tk.Tk()
    app = SimpleApp(root, title = 'Hello, world')
    root.mainloop()

basic()

Alternatively, you could use

    button.bind('<Return>', self.search)
    button.focus()

Doing it this way, pressing Return calls self.search() only when the button has the focus, but the button gets the focus when the app begins.


Regarding the use of *args and **kwargs:

**kwargs allows arbitrary keyword arguments to be passed to __init__.

When **kwargs is used in a function definition like this:

def __init__(self, master, **kwargs):

and we instantiate SimpleApp like this:

app = SimpleApp(root, title = 'Hello, world')

then Python sets kwargs to a dict containing the keyword arguments, e.g. {'title':'Hello, world'}. Note that **kwargs is Python syntax which can only be used in function definitions and function calls (see below), but kwargs itself is just a dict.

kwargs is then passed to Frame:

frame = tk.Frame(master, **kwargs)

Now, when **kwargs is used in a function call, the key-value pairs in the kwargs dict get expanded so that the above function call is equivalent to

frame = tk.Frame(master, title = 'Hello, world')

Since Frame can take numerous keyword arguments, and I don't know them all and don't wish to enumerate them, it is advantageous to use **kwargs. Note also that even if new keyword arguments were added to Frame at some later date, my code will still work, whereas if I spelled out the keywords explicitly then my code would not automatically "upgrade" if Frame's allowable keywords were to change.

*args, similarly, allows you to include arbitrary positional arguments to search:

def search(self,*args):

Python sets args to a list containing all the positional arguments sent to search when search is called.

I used *args here because self.search is called with no arguments or one argument.

When you say

button = tk.Button(frame, text = 'search', command = self.search)

self.search() is called with no argumens when the button is clicked. But when you say

    button.bind('<Return>', self.search)

self.search(event) is called with one argument when the Return key is pressed. event is a Tkinter.Event which has attributes (time, state, type, widget, x, y, etc) which allow you to learn more about what event took place.

Another, perhaps better, way to define search would have been

def search(self, event = None):
    ...

This would have made it clear that search may be passed 0 or 1 arguments, and not simply and arbitary number of arguments. It also would have provided easier access to event if an event were passed to search.

Reference:

Share:
16,531
Thomas
Author by

Thomas

Learning python basics in free time.

Updated on June 09, 2022

Comments

  • Thomas
    Thomas almost 2 years

    I bound the event <Return> to a Button, thinking that this would cause the command to be run after hitting Enter:

    Button(self.f, text="Print", command=self.Printer).pack(side=RIGHT, padx=10, pady=10)
    self.button1 = Button(self.f, text="search", command=self.search)
    self.button1.bind('<Return>', self.search)
    self.button1.pack(side=RIGHT, padx=10, pady=10)
    

    But it doesn't do anything. What must I do for self.search to be run when Enter is pressed?

  • Thomas
    Thomas over 12 years
    Thanks, now it's more clear for me. Just question what stands those: "**kwargs and *args" for?
  • unutbu
    unutbu over 12 years
    I added an explanation of why I used **kwargs and *args. If it's too long to read, see saltcrane's explanation.