joe
joe

Reputation:

How to set the tab order in a tkinter application?

I have been searching for a way to set the tab order in a tkinter application, that I have been working on. Currently the default order seems to be working from top-down, but it requires using CTRL + Tab to cycle through the controls.

Is there any way to customize the order and, more so, change the CTRL + Tab to just Tab?

Upvotes: 12

Views: 16187

Answers (2)

Anton Karton
Anton Karton

Reputation: 21

I've been searching for ways to skip some widgets while tabbing and found in tkinter's tk_focusNext function description the following: "A widget is omitted if it has the takefocus resource set to 0." you can set takefocus on widget initialization as an argument.

Upvotes: 0

Bryan Oakley
Bryan Oakley

Reputation: 385900

Tab order is based on the stacking order, which in turn defaults to the order that widgets are created. You can adjust the stacking order (and thus the tab order) using the methods tkraise (or lift) and lower.

This should be working out of the box for you without the need to press CTRL + Tab. Be aware, however, that tab inserts a literal tab in text widgets rather than moving focus to another control. That default behavior can be changed of course.

Here's an example showing how to reverse the tab order. When running the example, pressing tab in the first entry should take you to the last. Pressing tab again takes you to the second, then the first, lather, rinse, repeat

Note that the native Tk commands are raise and lower, but since raise is a reserved word in Python it had to be renamed in tkinter.

import Tkinter as tk


class SampleApp(tk.Tk):

    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)

        e1 = tk.Entry(self)
        e2 = tk.Entry(self)
        e3 = tk.Entry(self)

        e1.insert(0,"1")
        e2.insert(0,"2")
        e3.insert(0,"3")

        e1.pack()
        e2.pack()
        e3.pack()

        # reverse the stacking order to show how
        # it affects tab order
        new_order = (e3, e2, e1)
        for widget in new_order:
            widget.lift()


if __name__ == "__main__":
    app = SampleApp()
    app.mainloop()

Since you mention you have to do CTRL + Tab, I'm guessing you're trying to have the tab key change focus from a text widget. Normally a tab key inserts a literal tab. If you want it to change the focus, just add a binding to the <Tab> event.

Tkinter has a function that will return the name of the next widget that should get focus. Unfortunately, for older versions of Tkinter that function is buggy. However, it's easy to work around that. Here's a couple of methods you can add to the above code:

    def _focusNext(self, widget):
        '''Return the next widget in tab order'''
        widget = self.tk.call('tk_focusNext', widget._w)
        if not widget: return None
        return self.nametowidget(widget.string)

    def OnTextTab(self, event):
        '''Move focus to next widget'''
        widget = event.widget
        next = self._focusNext(widget)
        next.focus()
        return "break"

Upvotes: 21

Related Questions