The JFC Swing Tutorial: A Guide to Constructing GUIs (2nd Edition)
< Day Day Up > |
The JComponent class supports key bindings as a way of responding to individual keys typed by a user . Here are some examples of when key bindings are appropriate:
You often don't need to use key bindings directly. They're used behind the scenes by mnemonics (supported by all buttons ) and accelerators (supported by menu items). You can find coverage of mnemonics and accelerators in Enabling Keyboard Operation (page 282) in Chapter 7. An alternative to key bindings is using key listeners. [70] Key listeners have their place as a low-level interface to keyboard input, but for responding to individual keys, key bindings are more appropriate and tend to result in more easily maintained code. Some of the advantages of key bindings are that they're somewhat self-documenting ; take the containment hierarchy into account, encourage reusable chunks of code ( Action objects); and allow actions to be easily removed, customized, or shared. Also, they make it easy to change the key to which an action is bound. [70] See also How to Write a Key Listener (page 676) in Chapter 10. How Key Bindings Work
The key binding support provided by JComponent relies on the InputMap [71] and ActionMap [72] classes, which were introduced in v1.3. An input map binds keystrokes to action names , and an action map specifies the action corresponding to each action name . [73] Each JComponent has one action map and three input maps. The input maps correspond to the following focus situations: [71] InputMap API documentation: http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/InputMap.html. [72] ActionMap API documentation: http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/ActionMap.html. [73] Technically, you don't need to use action names in the maps; you can use any object as the "key" into them. By convention, however, you use a string that names an action. See also How to Use Actions (page 513).
Version Note: Prior to v1.3, the JComponent method registerKeyboardAction was used instead of input and action maps. registerKeyboardAction is now obsolete. (To ensure compatibility for older programs, registerKeyboardAction was reimplemented to use InputMap and ActionMap .)
When the user presses a key, the JComponent key event-processing code searches through one or more input maps to find a valid binding for it. When it finds a binding, it looks up the corresponding action in the action map. If the action is enabled, the binding is valid and the action is executed. If it's disabled, the search for a valid binding continues. If more than one binding exists for the key, only the first valid one found is used. Input maps are checked in this order:
Let's consider what happens in two typical key binding cases: a button reacting to the Space bar and a frame with a default button reacting to the Enter key. In the first case, assume that the user presses the Space bar while a JButton has the keyboard focus. First, the button's key listeners are notified of the event. Assuming none of the key listeners consumes the event (by invoking the consume method on the KeyEvent ), the button's WHEN_FOCUSED input map is consulted. A binding is found because JButton uses that input map to bind Space to an action name. The action name is looked up in the button's action map, and the actionPerformed method of the action is invoked. The KeyEvent is automatically consumed, and processing stops. In the second case, assume that the Enter key is pressed while the focus is anywhere inside a frame that has a default button (set using the JRootPane setDefaultButton method). Whatever the focused component is, its key listeners are first notified. Assuming that none of them consumes the key event, the focused component's WHEN_FOCUSED input map is consulted. If it has no binding for the key, the focused component's WHEN_ANCESTOR_ OF_FOCUSED_COMPONENT input map is consulted and then (if no binding is found) the WHEN_ANCESTOR_OF_FOCUSED_COMPONENT input maps of each of the component's ancestors in the containment hierarchy. Eventually, the root pane's WHEN_ANCESTOR_OF_FOCUSED_ COMPONENT input map is searched. Since that input map has a valid binding for Enter, the action is executed, causing the default button to be clicked. How to Make and Remove Key Bindings
Here's an example of specifying that a component should react to the F2 key: component.getInputMap().put(KeyStroke.getKeyStroke("F2"), "doSomething"); component.getActionMap().put("doSomething", anAction); //where anAction is a javax.swing.Action As shown, to get a component's action map you use the getActionMap method (inherited from JComponent ). To get an input map you use the getInputMap(int) method, where the integer is one of the JComponent.WHEN_*FOCUSED* constants. In the usual case where the constant is JComponent.WHEN_FOCUSED , you can just use getInputMap with no arguments. To add an entry to one of the maps, use the put method. Specify a key using a KeyStroke object, which you get using the KeyStroke.getKeyStroke(String) method. You can find examples of creating Action s (to put in an action map) in How to Use Actions (page 513). The following code is a slightly more complex example that specifies that a component should react to the Space bar as if the user clicked the mouse. component.getInputMap().put(KeyStroke.getKeyStroke("SPACE"), "pressed"); component.getInputMap().put(KeyStroke.getKeyStroke("released SPACE"), "released"); component.getActionMap().put("pressed", pressedAction); component.getActionMap().put("released", releasedAction); //where pressedAction and releasedAction are javax.swing.Action objects To make a component ignore a key that it normally responds to, use the special action name " none ." For example, the following code makes a component ignore the F2 key. component.getInputMap().put(KeyStroke.getKeyStroke("F2"), "none"); You specify the key corresponding to the action using a KeyStroke object. The preceding examples get KeyStroke objects using the KeyStroke.getKeyStroke(String) method.
Note: The preceding code doesn't prevent relevant WHEN_ANCESTOR_OF_FOCUSED_COMPONENT and WHEN_IN_FOCUSED_WINDOW input maps from being searched for an F2 key binding. To prevent this search, you must use a valid action instead of " none ." For example: Action doNothing = new AbstractAction() { public void actionPerformed(ActionEvent e) { //do nothing } }; component.getInputMap().put(KeyStroke.getKeyStroke("F2"), "doNothing"); component.getActionMap().put("doNothing", doNothing);
The Key Binding API
Tables 21 and 22 list the commonly used API for key bindings. Also see the API table Table 2, "Creating and Using an AbstractAction," on page 517. You can also refer to the API documentation for InputMap , KeyStroke , and ActionMap : http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/InputMap.html http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/KeyStroke.html http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/ActionMap.html Table 21. Getting and Using ActionMaps
Table 22. Getting and Using InputMaps
Examples That Use Icons
The following table lists just a few of the many examples that use ImageIcon .
|
< Day Day Up > |