Miguel Yurivilca
Miguel Yurivilca

Reputation: 464

Tkinter: When press 'Enter', then it goes to the next text box

So my teacher told me to learn Tkinter be myself and I try to understand it. Here's is the program I'm looking at.

It asks for a name and last name. (Yeah, Spanish is my native language)

When I finish inserting the name, I just want to press enter to go to the next text box which is last name.

from tkinter import *

master = Tk()
Label(master, text="Ingrese sus nombres: ").grid(row=0)
Label(master, text="Ingrese sus apellidos: ").grid(row=1)

e1 = Entry(master)
e2 = Entry(master)

e1.grid(row=0, column=1)
e2.grid(row=1, column=1)

mainloop()

Upvotes: 6

Views: 8582

Answers (2)

Alphard
Alphard

Reputation: 25

I 've found one solution about that.

if we have two entries like Entry_1 and Entry_2 then we want the cursor first stop in Entry_1 and when we press enter (or whatever we want other than "Return" key) the cursor will pass to the Entry_2.

entry_1.focus() 
entry_1.bind("<Return>",lambda funct1:entry_2.focus())

Upvotes: 0

Pier Paolo
Pier Paolo

Reputation: 920

A quick and dirty way would be to bind the first Entry widget to a function that switches the focus to the other widget:

def go_to_next_entry(event):
    e2.focus_set() # focus_set() switches the focus to the new widget

e1.bind('<Return>', go_to_next_entry)
# or, if you are familiar with lambdas, simply:
# e1.bind('<Return>', lambda e: e2.focus_set())

The .bind method expects as a first argument a string representing the type of user interaction, and as a second argument, a function of a single argument (the event argument. In this case you do not have to care about that, but if you were monitoring the movement of the cursor, the event could give you its coordinates.)


For a more general way, things get trickier and this method seems more an hack than anything. Anyway, if you have many entries, you can automate the method like so:

  1. Find all Entry widgets. They are children of master and you get them from master.winfo_children(), which gives the children in the order they were declared in the code. Be careful, though, because you get all the children (the Labels, too), so you have to filter the children (in this case the filter is "by type" and it is done with isinstance):

    entries = [child for child in master.winfo_children()
               if isinstance(child, Entry)]
    
  2. Then, you define the function that switches the focus to the desired widget:

    def go_to_next_entry(event, entry_list, this_index):
        next_index = (this_index + 1) % len(entry_list)
        entry_list[next_index].focus_set()
    

    The part next_index = (this_index + 1) % len(entries) cycles over the entries (if you press Return at the last entry, you go to the first one).

  3. Finally, you bind the switch function to each entry:

    for idx, entry in enumerate(entries):
        entry.bind('<Return>', lambda e, idx=idx: go_to_next_entry(e, entries, idx))
    

    The scary part is: lambda e, idx=idx: go_to_next_entry(e, entries, idx). The important part here, is that lambda is used to create another function (much like def) that has 2 arguments instead of the 3 required by go_to_next_entry. The idx=idx part makes it possible to call the newly-created function with just 1 parameter (as required by .bind.) To see why idx=idx is actually important and could not be omitted, have a look at Generate Tkinter buttons dynamically (which is about buttons, but the principle is the same.)

The complete code:

from tkinter import *

master = Tk()
Label(master, text="Ingrese sus nombres: ").grid(row=0)
Label(master, text="Ingrese sus apellidos: ").grid(row=1)

e1 = Entry(master)
e2 = Entry(master)
e3 = Entry(master)
e4 = Entry(master)

e1.grid(row=0, column=1)
e2.grid(row=1, column=1)
e3.grid(row=2, column=1)
e4.grid(row=3, column=1)

def go_to_next_entry(event, entry_list, this_index):
    next_index = (this_index + 1) % len(entry_list)
    entry_list[next_index].focus_set()

entries = [child for child in master.winfo_children() if isinstance(child, Entry)]
for idx, entry in enumerate(entries):
    entry.bind('<Return>', lambda e, idx=idx: go_to_next_entry(e, entries, idx))

mainloop()

Upvotes: 9

Related Questions