Easy to Learn Java: Programming Articles, Examples and Tips

Start with Java in a few days with Java Lessons or Lectures

Home

Code Examples

Java Tools

More Java Tools!

Java Forum

All Java Tips

Books

Submit News
Search the site here...
Search...
 

Chapter 2. (Introduction) Swing Mechanics. Easy for reading, Click here!

Custom Search
Chapter 2. (Introduction) Swing Mechanics. Easy for reading, Click here!

[ Return to Swing (Book) ]

Page: 13/14 



Previous Page Previous Page (12/14) - Next Page (14/14) Next Page
Subpages: 1. JComponent properties, size, and positioning 
2.  Event handling and dispatching 
3. Multithreading
4. Timers
5. AppContext service
6. Inside Timers & the TimerQueue
7. JavaBeans architecture
8. Fonts, Colors, Graphics and text
9. Using the Graphics clipping area
10. Graphics debugging
11. Painting and validation
12. Focus Management
13. Keyboard input, KeyStrokes, and Actions
14. SwingUtilities

2.13  Keyboard input, KeyStrokes, and Actions

2.13.1  Listening for keyboard input

KeyEvents are fired by a component whenever that component has the current focus and the user presses a key. To listen for these events on a particular component we can attach KeyListeners using the addKeyListener() method. KeyEvent extends InputEvent and, contrary to most events, KeyEvents are dispatched before the corresponding operation takes place (e.g. in a text field the operation might be adding a specific character to the document content). We can devour these events using the consume() method before they are handled further by key bindings or other listeners (below we'll discuss exactly who gets notification of keyboard input, and what order this occurs in).

There are three KeyEvent event types, each of which normally occurs at least once per keyboard activation (i.e. a press and release of a single keyboard key):

KEY_PRESSED: this type of key event is generated whenever a keyboard key is pressed. The key that is pressed is specified by the keyCode property and a virtual key code representing it can be retrieved with KeyEvent's getKeyCode() method. A virtual key code is used to report the exact keyboard key that caused the event, such as KeyEvent.VK_ENTER. KeyEvent defines numerous static int constants each starting with prefix "VK," meaning Virtual Key (see KeyEvent API docs for a complete list). For example, if CTRL-C is typed, two KEY_PRESSED events will be fired. The int returned by getKeyCode() corresponding to pressing CTRL will be a value matching KeyEvent.VK_CTRL. Similarly, the int returned by getKeyCode() corresponding to pressing the "C" key will be a value matching KeyEvent.VK_C. (Note that the order in which these are fired depends on the order in which they are pressed.) KeyEvent also maintains a keyChar property which specifies the Unicode representation of the character pressed (if there is no Unicode representation KeyEvent.CHAR_UNDEFINED is used--e.g. the function keys on a typical PC keyboard). We can retrieve the keyChar character corresponding to any KeyEvent using the getKeyChar() method. For example, the character returned by getKeyChar() corresponding to pressing the "C" key will be 'c'. If SHIFT was pressed and held while the "C" key was pressed, the character returned by getKeyChar() corresponding to the "C" key press would be 'C'. (Note that distinct keyChars are returned for upper and lower case characters, wheras the same keyCode is used in both situations--e.g. the value of VK_C will be returned by getKeyCode() regardless of whether SHIFT is held down when the "C" key is pressed or not. Also note that there is no keyChar associated with keys such as CTRL, and getKeyChar() will simply return '' in this case.)

KEY_RELEASED: this type of key event is generated whenever a keyboard key is released. Other than this difference, KEY_RELEASED events are identical to KEY_PRESSED events (however, as we will discuss below, they occur much less frequently).

KEY_TYPED: this type of event is fired somewhere between a KEY_PRESSED and KEY_RELEASED event. It never carries a keyCode property corresponding to the actual key pressed, and 0 will be returned whenever getKeyCode() is called on an event of this type. Note that for keys with no Unicode representation (such as PAGE UP, PRINT SCREEN, etc.), no KEY_TYPED event will be generated at all.

Most keys with Unicode representations, when held down for longer than a few moments, repeatedly generate KEY_PRESSED and KEY_TYPED events (in this order). The set of keys that exhibit this behavior, and the rate at which they do so, cannot be controlled and is platform-specific.

Each KeyEvent maintains a set of modifiers which specifies the state of the SHIFT, CTRL, ALT, and META keys. This is an int value that is the result of the bit-wise OR of InputEvent.SHIFT_MASK, InputEvent.CTRL_MASK, InputEvent.ALT_MASK, and InputEvent.META_MASK (depending on which keys are pressed at the time of the event). We can retrieve this value with getModifiers(), and we can query specifically whether any of these keys was pressed at the time the event was fired using isShiftDown(), isControlDown(), isAltDown(), and isMetaDown().

KeyEvent also maintains the boolean actionKey property which specifies whether the invoking keyboard key corresponds to an action that should be performed by that app (true) vs. data that is normally used for such things as addition to a text component's document content (false). We can use KeyEvent's isActionKey() method to retrieve the value of this property.

2.13.2  KeyStrokes

Using KeyListeners to handle all keyboard input on a component-by-component basis was required pre-Java 2. Because of this, a significant, and often tedious, amount of time needed to spent planning and debugging keyboard operations. The Swing team recognized this, and thankfully included functionality for key event interception regardless of which component currently has the focus. This functionality is implemented by binding instances of the javax.swing.KeyStroke class with ActionListeners (normally instances of javax.swing.Action).

Note: Registered keyboard actions are also commonly referred to as keyboard accelerators.

Each KeyStroke instance encapsulates a KeyEvent keyCode (see above), a modifiers value (identical to that of KeyEvent -- see above), and a boolean property specifying whether it should be activated on a key press (false -- default) or on a key release (true). The KeyStroke class provides five static methods for creating KeyStroke objects (note that all KeyStrokes are cached, and it is not necessarily the case that these methods will always return a brand new instance):

getKeyStroke(char keyChar)

getKeyStroke(int keyCode, int modifiers)

getKeyStroke(int keyCode, int modifiers, boolean onKeyRelease)

getKeyStroke(String representation)

getKeyStroke(KeyEvent anEvent)

The last method will return a KeyStroke with properties corresponding to the given KeyEvent's attributes. The keyCode, keyChar, and modifiers properties are taken from the KeyEvent and the onKeyRelease property is set to true if the event is of type KEY_RELEASED and false otherwise.

To register a KeyStroke/ActionListener combination with any JComponent we can use its registerKeyBoardAction(ActionListener action, KeyStroke stroke, int condition) method. The ActionListener parameter is expected to be defined such that its actionPerformed() method performs the necessary operations when keyboard input corresponding to the KeyStroke parameter is intercepted. The int parameter specifies under what conditions the given KeyStroke is considered to be valid:

JComponent.WHEN_FOCUSED: the corresponding ActionListener will only be invoked if the component this KeyStroke is registered with has the current focus.

JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT: the corresponding ActionListener will only be invoked if the component this KeyStroke is registered with is the ancestor of (i.e. it contains) the component with the current focus.

JComponent.WHEN_IN_FOCUSED_WINDOW: the corresponding ActionListener will be invoked if the component this KeyStroke is registered with is anywhere within the peer-level window (i.e. JFrame, JDialog, JWindow, JApplet, or any other heavyweight component) that has the current focus. Note that keyboard actions registered with this condition are handled in an instance of the private KeyBoardManager service class (see 2.13.4) rather than the component itself.

For example, to associate the invocation of an ActionListener corresponding to ALT-H no matter what component has the focus in a given JFrame, we can do the following:

  KeyStroke myKeyStroke =

    KeyStroke.getKeyStroke(KeyEvent.VK_H,

      InputEvent.ALT_MASK, false);

  myJFrame.getRootPane().registerKeyBoardAction(

    myActionListener, myKeyStroke,

    JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);

Each JComponent maintains a Hashtable client property containing all bound KeyStrokes. Whenever a KeyStroke is registered using the registerKeyboardAction() method, it is added to this structure. Only one ActionListener can be registered corresponding to each KeyStroke, and if there is already an ActionListener mapped to a particular KeyStroke, the new one will effectively overwrite the previous one.  We can retrieve an array of KeyStrokes corresponding to the current bindings stored in this Hashtable using JComponent's getRegisteredKeyStrokes() method, and we can wipe out all bindings by with the resetKeyboardActions() method. Given a KeyStroke object we can retrieve the corresponding ActionListener with JComponent's getActionForKeyStroke() method, and we can retrive the corresponding condition property with the getConditionForKeyStroke() method.

2.13.3  Actions

An Action instance is basically a convenient ActionListener implementation that encapsulates a Hashtable of bound properties similar JComponent's client properties (see chapter 12 for details about working with Action implementations and their properties). We often use Action instances when registering keyboard actions.

Note: Text components are special in that they use hierarchically resolving KeyMaps. A KeyMap is a list of Action/KeyStroke bindings and JTextComponent supports multiple levels of such mappings. See chapters 11 and 19.

2.13.4  The flow of keyboard input

Each KeyEvent is first dispatched to the focused component.  The FocusManager gets first crack at processing it. If the FocusManager doesn't want it, then the focused JComponent it is sent to calls super.processKeyEvent() which allows any KeyListeners a chance to process the event. If the listeners don't consume it and the focused component is a JTextComponent, the KeyMap hierarchy is traversed (see chapters 11 and 19 for more about KeyMaps). If the event is not consumed by this time the key bindings registered with the focused component get a shot. First, KeyStrokes defined with the WHEN_FOCUSED condition get a chance.  If none of these handle the event, then the component walks though it's parent containers (up until a JRootPane is reached) looking for KeyStrokes defined with the WHEN_ANCESTOR_OF_FOCUSED_COMPONENT condition. If the event hasn't been handled after the top-most container is reached, it is sent to KeyboardManager, a package private service class (note that unlike most service classes in Swing, KeyboardManager does not register its shared instance with AppContext -- see section 2.5). KeyboardManager looks for components with registered KeyStrokes with the WHEN_IN_FOCUSED_WINDOW condition and sends the event to them. If none of these are found then KeyboardManager passes the event to any JMenuBars in the current window and lets their accelerators have a crack at it.  If the event is still not handled, we check if the current focus resides in a  JInternalFrame (because it is the only RootPaneContainer that can be contained inside another Swing component).  If this is the case, we move up to the JInternalFrame's parent. This process continues until either the event is consumed or the top-level window is reached.



[ Return to Swing (Book) ]


Top 10 read Java Articles
 Get free "1000 Java Tips eBook"

 Java Calendar and Date: good to know facts and code examples

 Array vs ArrayList vs LinkedList vs Vector: an excellent overview and examples

 How can I convert any Java Object into byte array? And byte array to file object

 The Java Lesson 1: What is Java?

 How do I compare two dates and times, date between dates, time between times and

 Maven vs Ant or Ant vs Maven?

 How to open, read, write, close file(s) in Java? Examples on move, rename and de

 Java Array

 Java: JLabel font and color


[ More in News Section ]
Java Lessons

The Java Lesson 1:
What is Java?
The Java Lesson 2:
Anatomy of a simple Java program
The Java Lesson 3:
Identifiers and primitive data types
The Java Lesson 4:
Variables, constants, and literals
The Java Lesson 5:
Arithmetic operations, conversions, and casts
The Java Lesson 6:
Boolean expressions and operations
The Java Lesson 7:
Bitwise operations
The Java Lesson 8:
Flow control with if and else
The Java Lesson 9:
switch statements
The Java Lesson 10:
for, while, and do-while statements
The Java Lesson 11:
Using break and continue
The Java Lesson 12:
Class methods and how they are called
The Java Lesson 13:
Using the Math class
The Java Lesson 14:
Creating and calling custom class methods
The Java Lesson 15:
Overloading class methods
The Java Lesson 16:
An introduction to objects and object references
The Java Lesson 17:
The String class
The Java Lesson 18:
The StringBuffer class
The Java Lesson 19:
Initializing and processing arrays of primitives
The Java Lesson 20:
Initializing and processing arrays of objects
The Java Lesson 23:
Inheritance and overriding inherited methods
The Java Lesson 24:
abstract classes and polymorphism
The Java Lesson 25:
Interfaces, instanceof, and object conversion and casting
The Java Lesson 26:
Introduction to graphical programming and the java.awt packa
The Java Lesson 27:
The Component class
The Java Lesson 28:
Containers and simple layout managers
The Java Lesson 29:
The Color and Font classes
The Java Lesson 30:
Drawing geometric shapes
The Java Lesson 31:
Choice, List, and Checkbox controls
The Java Lesson 32:
Using the Scrollbar graphical control
The Java Lesson 33:
Menus and submenus
The Java Lesson 34:
An introduction to applets and the Applet class
The Java Lesson 35:
Essential HTML to launch an applet and pass it parameters
The Java Lesson 36:
Mouse event processing
Java Lesson 37:
Menus and submenus
Java Lesson 38:
The WindowListener interface and the WindowAdapter class
Java Lesson 39:
An introduction to GridBagLayout
Java Lesson 40:
An introduction to the Java Collections API
Java Lesson 41:
Exception handling with try, catch, and finally blocks
Java Lesson 42:
Claiming and throwing exceptions
Java Lesson 43:
Multithreading, the Thread class, and the Runnable interface
Java Lesson 44:
An introduction to I/O and the File and FileDialog classes
Java Lesson 45:
Low-level and high-level stream classes
Java Lesson 46:
Using the RandomAccessFile class
Java Lessons by
Joh Huhtala: Update

Latest articles
 Java Profiler JProbe to Resolve Performance Problems Faster

 SSL with GlassFish v2, page 5

 SSL with GlassFish v2, page 4

 SSL with GlassFish v2, page 3

 SSL with GlassFish v2, page 2

 The Java Lesson 2: Anatomy of a simple Java program, page 2

 New site about Java for robots and robotics: both software and hardware.

 Exceptions -III: What's an exception and why do I care?

 Exceptions -II: What's an exception and why do I care?

 Exceptions: What's an exception and why do I care?

 Double your Java code quality in 10 minutes, here is receipt

 Murach's Java Servlets and JSP

 How to get ascii code from a char in Java?

 Can we just try without catch? Yes!

 Make Tomcat page load faster

 Make your Tomcat More secure - limit network address for certain IP addresses

 New Java book online starts now here...

 Implementing RESTful Web Services in Java

 Firefox trimming from 1 GB to 40 Mb with many tabs opened

 SSL with GlassFish v2

 My request to replublish Tech Tips

 Search JavaFAQ.nu site here

 New Advanced Installer for Java 6.0 brings XML updates and imports 3rd party MSI

 EJB programming restrictions

 Maven vs Ant or Ant vs Maven?

 Why Java does not use default value which it should?

 How to unsign signed bytes in Java - your guide is here

 The Java Lesson 3: Identifiers and primitive data types. Page 2

 The Java Lesson 7: Bitwise operations with good examples, click here! Page 4

 The Java Lesson 7: Bitwise operations with good examples, click here! Page 3


[ More in News Section ]


Home Code Examples Java Forum All Java Tips Books Submit News, Code... Search... Offshore Software Tech Doodling

RSS feed Java FAQ RSS feed Java FAQ News     

    RSS feed Java Forums RSS feed Java Forums

All logos and trademarks in this site are property of their respective owner. The comments are property of their posters, all the rest 1999-2006 by Java FAQs Daily Tips.

Interactive software released under GNU GPL, Code Credits, Privacy Policy