Search code examples
pythontkinterwidgetfocus

Focus switch in TKinter widgets not working programmatically


I have TKinter app with a window with just two widgets: a Listbox and an Entry. Now, I want that whenever a user click on an item in the Listbox, the focus switch immediately to the Entry. But neither Entry.focus_set() nor Entry.focus_force() are working. Is there a way to make it work?

lb = Listbox(root)
lb.pack()
lb.bind('<<ListboxSelect>>', sel_done)
entry = Entry(root)
entry.pack()


def sel_done():
    entry.focus_set()

Thanks for your attention.


Solution

  • Some issues I see are:

    • Binding to '<<ListboxSelect>>' will trigger the event callback sel_done when the mouse button is pressed, but then the Listbox will take focus as soon as the mouse button is released. To fix this, you can instead bind to '<ButtonRelease>'
    lb.bind('<ButtonRelease>', sel_done) 
    
    • The event binding automatically passes an event argument to the bound function, so either sel_done will need to accept this argument (even if you're not using it) or you can absorb it using a lambda (an anonymous function)

    OPTION ONE - have sel_done accept the extra argument

    # you can call this parameter whatever you like, but typically "event" is used
    # and the leading _underscore implies that this value is ignored/unused
    def sel_done(_event):
        entry.focus_set()  # FWIW, you can also just use 'focus()'
    

    OPTION TWO - use a lambda in the event binding itself

    # note the () after 'sel_done' - this is because we're actually binding to an
    # anonymous function, and then telling *that* function to call 'sel_done()';
    # the _event arg is "absorbed" by the lambda and can be safely ignored
    lb.bind('<ButtonRelease>', lambda _event: sel_done())