Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Focus on Swing

Explore focus management with JFC's Swing components

  • Digg
  • Reddit
  • SlashDot
  • Stumble
  • del.icio.us
  • Technorati
  • dzone
Focus is the mechanism that determines which of the components in a window will receive keyboard input events. A focus manager looks for special keystrokes that change the focus (usually the Tab and Shift-Tab keys), and then decides which component will next get the focus. Often, you'll want to control how the focus moves between components, especially if you're designing a complex form or dialog for users to enter information.

Java has had a focus manager for AWT components since version 1.0 of the Java Development Kit (JDK), and developers have howled about its inadequacies ever since. Well, it's time to stop howling. The focus management services provided with the Java Foundation Classes (JFC) should satisfy all of your needs for controlling focus changes.

A bit of history

The only way to manage focus changes with JDK 1.0 is through a few methods in the Component class. JDK 1.0 allows components to set the focus to themselves with requestFocus and to change the focus to the next component with nextFocus. Other than getting notification of focus changes with gotFocus and lostFocus, that's pretty much all you can do.

JDK 1.1 deprecates nextFocus and replaces it with transferFocus, which provides exactly the same functionality as nextFocus. Likewise, 1.1 deprecates gotFocus and lostFocus and replaces them with the addFocusListener method to support focus change notification using the 1.1 event model.

Neither JDK 1.0 nor 1.1 provide any means for applications to override the behavior of the focus manager, or to change the algorithm used to determine focus traversal.

What's new with Swing's focus management

Swing provides some powerful new ways to manage focus changes at the component level. Here's what you can do with focus management at that level:

  • Set the focus to a given component
  • Transfer the focus to the next component in the focus-change order
  • Determine if a component has the focus
  • Disable a component from responding to focus requests
  • Allow the component that currently has the focus to manage the next focus change


And if this isn't enough to meet your focus control needs, Swing allows you to create and use your own custom focus manager.

Let's take a quick look at the relationship between the AWT and Swing focus managers. The following figure shows how JFC incorporates both the AWT and Swing focus managers.

AWT and Swing focus manager relationship

Note that the AWT focus manager will manage focus for Swing components because they are extended AWT components. However, the flip side is not true: The Swing focus manager will not manage focus for AWT components. The section "Mixing AWT and Swing components" explains how to handle focus management if you're mixing these two component types in an application.

Explicitly setting the focus

There are two JComponent methods that allow you to explicitly set the focus to a given component: requestFocus and grabFocus. If you've worked with AWT components, you're probably familiar with the requestFocus method. Swing overrides this Component method with an implementation that allows you to call the new setRequestFocusEnabled method. This method can enable or disable the component from getting the focus via requestFocus.

However, you can't use setRequestFocusEnabled to prevent a component from getting the focus via the focus manager. That's because the focus manager uses a new Swing method, grabFocus, to give components the focus. grabFocus works just like requestFocus, except that you can't disable it. The Swing docs say that only focus managers should use grabFocus.

Let's take a look at a bit of sample code written for components. This code will cause a component to get the focus whenever the component is under the mouse:

// add a listener for mouse enter
addMouseListener(new MouseAdapter() {
    public void mouseEntered(MouseEvent event) {
        // Request the focus (if don't already have it)
        if(!hasFocus()) { requestFocus(); }
    }
});


This fragment adds a mouse listener, which is implemented in an anonymous inner class based on the MouseAdapter adapter class. The mouse adapter's mouseEntered method is called whenever the mouse passes over the component. The implementation for mouseEntered calls hasFocus to see if the component already has the focus, and if it doesn't, calls requestFocus to give the component the focus. A slightly more fail-safe way to set the focus would be:

if(!hasFocus()) {
    // ensure requestFocus is enabled
    if(!isRequestFocusEnabled()) { setRequestFocusEnabled(true); }
    requestFocus();
}
And if you're writing a focus manager, you can use

grabFocus:

if(!hasFocus()) { grabFocus(); }


Transferring the focus

Like AWT 1.1, Swing provides the means for a component to transfer the focus to the next component with the transferFocus method.

public void transferFocus();


This method can be useful for implementing components that automatically advance the focus when the user has completed whatever task or purpose is served by the component (like choosing from a group of radio buttons or items in a list). transferFocus is not really useful for explicitly setting the focus -- you would have to know which component has the focus just before the component that you actually want to set the focus to.

Detecting focus changes

Swing doesn't bring any changes to the operation of AWT 1.1's focus listener implementation. I'll give a brief description of focus listeners for those readers that aren't familiar with them; if you know this stuff you may want to skip on to the next section.

Focus listeners provide a means of notifying applications when components gain or lose the focus. The adapter class for focus events, FocusAdapter, has two methods: focusGained and focusLost. The addFocusListener and removeFocusListener methods add and remove focus listeners for components. Standard event-listener stuff -- nothing fancy here. Let's glance at a piece of code. The following code fragment adds a focus listener that changes the background color when a component gets the focus.

// private instance variables
private boolean bFocusIndicated = false;
private Color originalColor;
.
.
.
// add a listener for focus events
addFocusListener(new FocusAdapter() {
    public void focusGained(FocusEvent e) {
        if(!bFocusIndicated) {
            // set background to a darker color to indicate focus
            originalColor = getBackground();
            setBackground(originalColor.darker());
            bFocusIndicated = true;
        }
    }
    public void focusLost(FocusEvent e) {
        // restore original background color
        setBackground(originalColor);
        bFocusIndicated = false;
    }
});


You can't always count on getting focusGained and focusLost events in matched pairs, hence the need for the bFocusIndicated variable to keep up with whether we've indicated focus on a component.

  • Digg
  • Reddit
  • SlashDot
  • Stumble
  • del.icio.us
  • Technorati
  • dzone
Comments (2)
Login
Forgot your account info?

wow, the first comment after more than 10 year!!! swing rocks :-By Anonymous on June 4, 2009, 1:50 amwow, the first comment after more than 10 year!!! swing rocks :-)

Reply | Read entire comment

Sweet.By Anonymous on April 22, 2009, 12:28 amframe.requestFocus(); Thumbs up bro. I got sick of my buttons being focused with little dotted lines and stuff after you clicked them. Makes my application just...

Reply | Read entire comment

View all comments

Add comment
Anonymous comments subject to approval. Register here for member benefits.
Have a JavaWorld account? Log in here. Register now for a free account.