When your application is running, you can force a widget to have the keyboard focus by calling focus on that widget:
$widget->focus;
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.
To make the focus follow the mouse around, use focusFollowsMouse:
$widget->focusFollowsMouse;
To find out which widget has the focus, call focusCurrent:
$who = $widget->focusCurrent;
To force a widget to have the focus even if the application isn't currently active, call focusForce:
$widget->focusForce;
This is not a nice thing to do, so try to not use it.
To find out which widget had the focus last, call focusLast:
$which = $widget->focusLast;
If none of the widgets in the window has the focus, the Toplevel is returned.
You can use the focusNext and focusPrev methods to actually move the focus to the next or previous widget in focus order:
$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.
What should you do when you don't want to use your mouse in your Perl/Tk application? There are ways you can move around in your application without having to touch the mouse.
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).
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.
One of the more common things you'll want to do with your application is allow shortcuts to commands that are in menus. Here is a typical file menu being created:
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.