0

I'm trying to return the focus to the first entry. If you move the focus to the next entry or the button and the you click on the button, the focus returns fine to first entry. When I try doing the same thing by using the tab key, the focus_set method fails. I've tried many different ways, but the result is always the same. Anyone knows why? And might be so kind as to showing me how to do it right? Thanks in advance.

This is what I got so far:

from tkinter import *
w = Tk()

def focus():
    box1.focus_set()

def check(event):
    if str(event.widget) == '.!entry2':
        print('focus back to box1')
        focus()

box1 = Entry(w, width=15)
box2 = Entry(w, width=15)
box1.focus_set()
box2.bind('<Tab>', check)
box1.pack()
box2.pack()

btn = Button(w, text='Box 1 Focus', command=focus)
btn.pack()
w.mainloop()
Bert_AT
  • 95
  • 8
  • 1
    Tested your code and it works for me. If I press 1 the focus moves if I tab to the button and press space or click on it the focus moves. If I tab to the 2nd entry box then press the button the focus moves. Are you not seeing this on your end? – Mike - SMT Aug 16 '18 at 02:00
  • @Mike - SMT - Hi, Mike! When the focus is on entry2 and I click on the button, or when I tab the focus to the button from entry2 and then I click the button, the focus returns to entry1 as expected. I expected the same to happen, when the focus is on entry2 and I hit the tab key. I want the focus to go back to box1, but instead I goes to the button, at least on **my** end. Is it different on your end? – Bert_AT Aug 16 '18 at 07:29

1 Answers1

1

If I run your code, str(event.widget) is something like ".36580648", not ".!entry2". You can give your widget a custom name like

box2 = Entry(w, width=15, name='second')

You can then check if str(event.widget) == '.second'.
Alternatively, you can just check if event.widget == box2: which is easier and less prone to error.

If you do one of these things, you will see that 'focus back to box1' is printed, but the focus is still transferred to the button instead of the label. This is because your custom event is triggered before the default event for <Tab>, which is to move focus to the next widget. You can stop the default event handling by returning 'break' in your function.

The complete example would become:

from tkinter import *
w = Tk()

def focus():
    box1.focus_set()

def check(event):
    if event.widget == box2:
        print('focus back to box1')
        focus()
        return 'break'

box1 = Entry(w, width=15)
box2 = Entry(w, width=15)
box1.focus_set()
box2.bind('<Tab>', check)
box1.pack()
box2.pack()

btn = Button(w, text='Box 1 Focus', command=focus)
btn.pack()
w.mainloop()
fhdrsdg
  • 10,297
  • 2
  • 41
  • 62
  • Nifty solution!!! Yes, I did notice **custom event is triggered before** when I used `FocusOut` with a new handler instead. Still, I don't understand why `'break'`works since it's just a regular string. `.!entry2` was the reading I got when I bound box2 to a Button pattern and printed the `event.widget` in the handler, but I like your approach better. It's what I wanted to apply, but wasn't sure how. Thanks a lot. – Bert_AT Aug 16 '18 at 09:06
  • 1
    You're welcome. For a nice explanation about event handling in tkinter and the returning of `'break'` (you're right that it's just a string, but tkinter checks for it specifically), read [this answer](https://stackoverflow.com/a/11542200/3714930). – fhdrsdg Aug 16 '18 at 09:27