Reputation: 23593
I couldn't find a concise answer about the relationships among all these, so that I can pick up best practices and get going. JTextComponent
has:
The old addKeyListener(..)
. We write a KeyListener
with methods that get called on keyPressed(..)
, keyTyped(..)
, etc. events, which we can query: event.getKeyCode()
.
addKeymap(..)
and setKeymap(..)
. A Keymap
has addActionForKeyStroke(..)
, which takes a KeyStroke
(that we can get by calling KeyStroke
's static methods specifying the character or key code), and an Action
, which is an ActionListener
with bells and whistles.
getInputMap(..)
and getActionMap(..)
. An InputMap
maps a KeyStroke
(as above) to a String
, and the ActionMap
maps the string to an Action
(as above). The Java Tutorial How to use key bindings talks about that.
These are three redundant ways of attaining the same functionality. Besides comparative advantages/disadvantages, this raises the natural question of how these three mechanisms co-exist? Which ones take priority over others?
Upvotes: 3
Views: 1592
Reputation: 23593
InputMap
+ ActionMap
system was introduced in 1.3 and replaced the older Keymap
(which was reimplemented using the InputMap
+ ActionMap
system under the hood, for backwards-compatibility). The new system has a superset of the capabilities of Keymap
. (From the O'Reilly book Java Swing by Loy and Eckstein, on page 755.)
Therefore, we don't need to worry about Keymap
for new code.
The Java Tutorial in How to use key bindings doesn't even mention Keymap
, but it does address KeyListener
s vs key bindings (i.e. the InputMap
+ ActionMap
facilities):
The KeyListener
s approach takes more work because of issues of focus and component containment hierarchy (which it's unaware of). For example, if we have a table component and a table-cell component contained in it, which has focus, pressing the ↑ key will send events to the table cell component, and it will be up to us to relay them to the table (because we want to change the table's currently selected cell).
In contrast, key bindings let us specify the binding on the parent component directly: each JComponent
has three InputMap
s and one ActionMap
. The input maps are of these types: JComponent.WHEN_FOCUSED
, WHEN_ANCESTOR_OF_FOCUSED_COMPONENT
and WHEN_IN_FOCUSED_WINDOW
. Unlike with listeners, where all of the KeyListener
s on the focused component only are processed in order, with key bindings the event will propagate up the hierarchy (well, a tree I think, as there is only one parent per component) until it finds an action (that hasn't been disabled), which is when it stops. The second type of InputMap
takes priority over the third during this search.
The KeyListener
s take precedence over the key binding mechanism. While the KeyListener
s of a component are being processed, one of them may e.consume()
, and then the event won't reach further KeyListener
s, nor the key binding hierarchy. Last-added key listeners are processed first.
So, while the key bindings approach takes a bit more hassle to set up from scratch (you have to give the Action
a name, and call two methods to bind it to both a KeyStroke
via an InputMap
and an AbstractAction
via the ActionMap
), it seems that it should be the first point of call for assigning a function to be called in response to a key press. KeyListener
s enable you to do more (e.g. exotic key combinations — beyond what KeyStroke
can handle; and allow earlier access to the key event, with the ability to e.consume()
it), but key bindings are more convenient, anticipating the basic use cases as they do.
A relevant point (suggested by a related question) is yet another redundant mechanism for dealing with text components especially: DocumentListener
s and DocumentFilter
s. These are even more convenient and pitfall-proof for when the reason for remapping keys is to control what happens to the text in a text component.
See also: a report about the details of how the key bindings system works from the time when it was introduced, archived version.
Upvotes: 8