13.16. Focus Methods
You might want to do this if you have an Entry widget into which the user should start typing first. Calling focus right before MainLoop causes the widget to get the focus right away. If you press the Tab key, the focus automatically changes from one widget to the next. Shift-Tab can be used to change the focus to the previous widget. Control-Tab can be used in the Text widget. When in doubt, remember that you can tell when a widget has the focus by the highlight rectangle around it.
There are several methods that allow you to manipulate the focus.
$who = $widget->focusCurrent;
This is not a nice thing to do, so try to not use it.
$which = $widget->focusLast;
If none of the widgets in the window has the focus, the Toplevel is returned.
$nextwidget = $widget->focusNext; $prevwidget = $widget->focusPrev;
So, what is focus order? First, focus order is constrained to $widget's Toplevel and the Toplevel's descendant widgets. focusNext follows the stacking order of $widget's children as it tries to determine which is the next widget to receive the focus. As it happens, the widget lowest (first) in the stacking order is the most eligible window to receive the focus. The search is then depth-first: the first widget in the stacking order and all its children are considered first, then the first widget's siblings.
Once a candidate widget to receive the focus is determined, the candidate widget's -takefocus option is evaluated. If -takefocus is 0, the widget never gets the focus. If 1, then the widget gets the focus. If undef, then Tk decides. Otherwise, the value of -takefocus is a standard callback, which should return 0, 1, or undef.
focusPrev sets the focus to the previous widget in the focus order.
13.16.1. Keyboard Traversal
22.214.171.124. Tabbing between widgets
Run any of the Perl/Tk applications you have and hit the Tab key. Assuming you haven't bound Tab to anything else, you'll see different widgets in your application get the focus, each in turn. You know a widget has the focus by a variety of ways. A Button will have a dotted or solid line drawn around it that wasn't there before it had the focus. An Entry will automatically select all the text in it when it has the focus. Only one widget in your application can have the focus at a time. When that widget has the focus, you are able to interact with it using the keyboard. With a widget such as Entry, this makes complete sense. You need to be able to type text into it using the keyboard. We'll talk about this in more detail in the next section.
Not all widgets will take the focus. A Label doesn't accept any keyboard or mouse input, so it won't ever get the focus. A Text widget is special because once it has the focus, a Tab is rebound to enter a Tab as part of the Text. Check with documentation on each widget to determine if you can Tab out of the widget or not.
The order in which the focus moves around matches the order that you packed the widgets into your application. If you are going to rely on using the Tab key to move between widgets in a logical fashion, you may need to redesign the packing order. Try using Shift-Tab; you'll now be moving between widgets in backwards order. Sometimes when Tab has been rebound to do something else, you can use Shift-Tab to get out of the widget and on to the next one (e.g., a Text widget).
126.96.36.199. Default widget bindings
So what happens when you start hitting other keys and a widget has the focus? A lot depends on what widget has the focus, because there are different built-in bindings for each widget. A Button will let you hit the spacebar to invoke it (this is true for a Button, Checkbutton, or Radiobutton). An Entry or Text widget will let you start typing text into the widget. A Listbox will let you use the arrow keys to move between different items in it. Each widget has its own set of default bindings that let you use the keyboard to interact with it. Check the documentation for each widget to determine what the default bindings are. You can also take a look at the bindDump module shown in Chapter 15, "Anatomy of the MainLoop" to get some interactive information about a widget.
188.8.131.52. Menu Traversal
my $filem = $menubar->cascade(-label => "~File", -tearoff => 0); $filem->command(-label => "~Open...", -command => \&open_file, -accelerator => "Ctrl+O"); $filem->command(-label => "~Close", -command => \&close_file, -accelerator => "Ctrl+W"); $filem->command(-label => "~Save", -command => \&save_file, -accelerator => "Ctrl+S"); $filem->command(-label => "Save ~As...", -command => \&saveas_file);
You'll see we used the -accelerator option, which will show on the right side of the menu when it's dropped down. (See Figure 12-1 back in Chapter 12, "The Menu System" for an example of accelerators.) This doesn't do anything but put text on the screen. In order to have something happen when the user clicks on "Control-W," you need to add a binding like this:
$mw->bind($mw, "<Control-s>" => \&save_file); $text->bind("Tk::Text", "<Control-s>" => \&save_file);
By using bind on the MainWindow widget, we've effectively bound that key combination for all widgets in the application. No matter which widget has the focus, you'll be able to type Control-s and invoke the save_file method.
The second binding on the Text widget is necessary only in some cases where the Text widget will actually parse the entered command to try and insert text into the widget. Without that additional binding, you'll get a funny little rectangle if the Text widget has the focus and you'll type Control-s. This type of conflict reminds us to check out the default bindings for each widget we are using in our application. We might be replacing default widget functionality.
Take a look at Chapter 15, "Anatomy of the MainLoop" for more information on bindings and the different ways to create them.
Copyright © 2002 O'Reilly & Associates. All rights reserved.