Subpages: 1. JComponent properties, size, and positioning
2. Event handling and dispatching
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
2.12 Focus Management
When Swing components are placed in a Swing container, the route of keyboard focus is, by default, left to right and top to bottom. This route is referred to as a focus cycle, and moving focus from one component to the next in a cycle is accomplished using the TAB key or CTRL-TAB. To move in the reverse direction through a cycle we use SHIFT-TAB or CTRL-SHIFT-TAB. This cycle is controlled by an instance of the abstract FocusManager class.
FocusManager relies on five JComponent properties of each component to tell it how to treat each component when the current focus reaches or leaves it:
focusCycleRoot: this specifies whether or not the component contains a focus cycle of its own. If it contains a focus cycle, focus will enter that component and loop through its focus cycle until it is manually or programatically moved out of that component. By default this property is false (for most components), and it cannot be assigned with a typical setXX() accessor. It can only be changed through overriding the isFocusCycleRoot() method and returning the appropriate boolean value.
managingFocus: this specifies whether or not KeyEvents corresponding to a focus change will be sent to the component itself or intercepted and devoured by the FocusManager. By default this property is false (for most components), and it cannot be assigned with a typical setXX() accessor. It can only be changed through overriding the isManagingFocus() method and returning the appropriate boolean value.
focusTraversable: this specifies whether or not focus can be transfered to the component by the FocusManager due to a focus shift in the focus cycle. By default this property is true (for most components), and it cannot be assigned with a typical setXX() accessor. It can only be changed through overriding the isFocusTraversable() method and returning the appropriate boolean value. (Note that when focus reaches a component through a mouse click its requestFocus() method is called. By overriding requestFocus() we can respond to focus requests on a component-specific basis.)
requestFocusEnabled: this specifies whether or not a mouse click will give focus to that component. This does not affect how the FocusManager works, which will continue to transfer focus to the component as part of the focus cycle. By default this property is true (for most components), and it can be assigned with JComponent's setRequestFocusEnabled() method.
nextFocusableComponent: this specifies the component to transfer focus to when the TAB key is pressed. By default this is set to null, as focus traversal is handled for us by a default FocusManager service. Assigning a component as the nextFocusableComponent will overpower FocusManager's focus traversal mechanism. This is done by passing the component to JComponent's setNextFocusableComponent() method.
abstract class javax.swing.FocusManager
This abstract class defines the responsibility of determining how focus moves from one component to another. FocusManager is a service class whose shared instance is stored in AppContext's service table (see 2.5). To access the FocusManager we use its static getCurrentManager() method. To assign a new FocusManager we us the static setCurrentManager() method. We can disable the current FocusManager service using the static disableFocusManager() method, and we can check whether it is enabled or not at any given point using the static isFocusManagerEnabled() method.
The following three abstract methods must be defined by sub-classes:
focusNextComponent(Component aComponent): should be called to shift focus to the next component in the focus cycle whose focusTraversable property is true.
focusPreviousComponent(Component aComponent): should be called to shift focus to the previous focusable component in the focus cycle whoe focusTraversable property is true.
processKeyEvent(Component focusedComponent, KeyEvent anEvent): should be called to either consume a KeyEvent sent to the given component, or allow it to pass through and be processed by that component itself. This method is normally used to determine whether a key press corresponds to a shift in focus. If this is determined to be the case, the KeyEvent is normally consumed and focus is moved forward or backward using the focusNextComponent() or focusPreviousComponent() methods respectively.
DefaultFocusManager extends FocusManager and defines the three required methods as well as several additional methods. The most significant method in this class is compareTabOrder(), which takes two Components as parameters and determines first which component is located closer to the top of the container acting as their focus cycle root. If they are both located at the same height this method will determine which is left-most. A value of true will be returned if the first component passed in should be given focus before the second. Otherwise false will be returned.
The focusNextComponent() and focusPreviousComponent() methods shift focus as expected, and the getComponentBefore() and getComponentAfter() methods are defined to return the previous or next component, respectively, that will receive the focus after a given component in the focus cycle. The getFirstComponent() and getLastComponent() methods return the first and last component to receive focus in a given container's focus cycle.
The processKeyEvent() method intercepts KeyEvents sent to the currently focused component. If these events correspond to a shift in focus (i.e. TAB, CTRL-TAB, SHIFT-TAB, and SHIFT-CTRL-TAB) they are consumed and the focus is changed accordingly. Otherwise these events are sent to the component for processing (see section 2.13). Note that the FocusManager always has first crack at keyboard events.
2.12.3 Listening for focus changes
As with AWT components, we can listen for focus changes on a component by attaching an instance of the java.awt.FocusListener interface. FocusListener defines two methods, each of which take a java.awt.FocusEvent instance as parameter:
focusGained(FocusEvent e): this method receives a FocusEvent when focus is given to a component this listener is attached to.
focusLost(FocusEvent e): this method receives a FocusEvent when focus is removed from a component this listener is attached to.
FocusEvent extends java.awt.ComponentEvent and defines, among others, the FOCUS_LOST and FOCUS_GAINED ids to distinguish between its two event types. A FOCUS_LOST event will occur corresponding to the temporary or permanent loss of focus. Temporary loss occurs when another app or window is given focus. When focus returns to this window, the component that originally lost the focus will once again gain the current focus, and a FOCUS_GAINED event will be dispatched at that time. Permanent focus loss occurs when the focus is moved by either clicking on another component in the same window, programmatically invoking requestFocus() on another component, or dispatching of any KeyEvents that cause a focus change when sent to the current FocusManager's processKeyEvent() method. As expected, we can attach and remove FocusListener implementations to any Swing component using Component's addFocusListener() and removeFocusListener() methods respectively.