Programmatic Focus Traversal in Java V1.4

Baldwin shows you three different ways to control the focus programmatically with Java V1.4.

Published:  October 7, 2003
By Richard G. Baldwin

Java Programming Notes # 1852


Preface

New features in SDK Version 1.4.0

The recently released JavaTM 2 SDK, Standard Edition Version 1.4 contains a large number of new features, including many changes and additions to the focus subsystem.  This lesson is part of a series of lessons designed to teach you how to use the new features of the focus subsystem in Java Version 1.4 and later.

The first lesson in the series was entitled Focus Traversal Policies in Java Version 1.4.  The previous lesson was entitled Changing Focus Traversal Keys in Java V1.4.

Previous topics

Previous lessons have dealt with several aspects of the new focus subsystem, including:

This lesson deals with writing program code to control the focus. 

Viewing tip

You may find it useful to open another copy of this lesson in a separate browser window.  That will make it easier for you to scroll back and forth among the different listings and figures while you are reading about them.

Supplementary material

I recommend that you also study the other lessons in my extensive collection of online Java tutorials.  You will find those lessons published at Gamelan.com.  However, as of the date of this writing, Gamelan doesn't maintain a consolidated index of my Java tutorial lessons, and sometimes they are difficult to locate there.  You will find a consolidated index at www.DickBaldwin.com.

Preview

In this lesson, I will show you three different ways to control the focus programmatically.  One way will cause the focus to traverse components according to the focus traversal policy, relative to the current focus owner.

The second way will cause the focus to traverse components according to the focus traversal policy, but relative to a specified component.  I will show you two different ways to accomplish this.

The third way will cause a specified component to gain the focus.

Discussion and Sample Code

Focus traversal

Sun defines focus traversal as "the user's ability to change the "focus owner" without moving the cursor."

Focus traversal can normally be either forward to the next component, or backward to the previous component.

Traversal typically uses keys

Typically, focus traversal is accomplished using one or more keys on the keyboard.  For example, it is very common for the TAB key to be used to move the focus along its traversal path in the forward direction, and for the Shift-TAB key combination to be used to move the focus along its traversal path in the backward direction.

Keyboard is not required

However, keyboard action isn't always required.  It is also possible for program code to initiate traversal through the execution of program instructions.  That is the primary topic of this lesson.

FocusTraversalPolicy

The AWT focus implementation determines which component to focus next based on the FocusTraversalPolicy of the focus owner's focus cycle root.  (The FocusTraversalPolicy was the subject of a previous lesson.)

Description of the program

This lesson presents a program named FocusTraversal02 that illustrates three different ways to control the focus programmatically.

The graphical user interface

The program displays the graphical user interface (GUI) shown in Figure 1.

Figure 1.  Sample program user interface.

The numbers on a clock

A single JFrame object appears on the screen.  Four JButton objects appear at the North, South, East, and West locations in the frame.  The buttons display the captions 03, 06, 09, and 12.

 (The positions of the buttons with their captions mimic four of the numbers on a clock.)

Three JLabel objects

Three JLabel objects with labels A, B, and C appear in the center of the frame.

Keyboard-generated focus traversal

When the program first starts running, the button with the caption 12 has the focus.

Successively pressing the TAB key causes the focus to traverse the buttons in a clockwise direction:  12, 03, 06, 09 and back to 12.

Holding down the Shift key and successively pressing the TAB key causes the focus to traverse the buttons in a counter-clockwise direction:  12, 09, 06, 03, and back to 12.

(The traversal path described above illustrates the use of a custom focus traversal policy, which was discussed in an earlier lesson.)

Programmatic focus traversal

This program also supports programmatic focus traversal based on mouse clicks.  Successively clicking the A in the center of the frame (see Figure 1) causes the same traversal result as successively pressing the TAB key.

Holding down the Shift key and successively clicking the A causes the same result as holding down the Shift key and successively pressing the TAB key.

In other words, the result of clicking the letter A replicates the pressing of the TAB key.  This illustrates programmatic focus traversal.

Moving the focus to a specific component

Clicking the letter B causes the button with the 12 to gain the focus.

Traversal relative to a specific component

The result of clicking the letter C is somewhat more difficult to explain.  This causes the next component following the button with the 12 in the focus traversal policy (the button with the 03) to gain the focus.

Holding down the Shift key and clicking the letter C causes the previous component before the button with the 12 in the focus traversal policy (the button with the 09) to gain the focus.

In other words, clicking the letter C causes the same behavior that would occur from pressing the TAB key when the button with the 12 already has the focus.

Requires Version 1.4 or later

This program requires SDK V1.4 or later.  It was tested using SDK 1.4.1 under WinXP

Will discuss sample program in fragments

As is my habit, I will discuss the program in fragments.  A complete listing of the program is provided in Listing 12 near the end of the lesson.

Get a GUI object

Listing 1 shows the main method, which simply instantiates a new object of the GUI class.  The graphical user interface shown in Figure 1 is a visual manifestation of that object.

public class FocusTraversal02 {
public static void main(String[] args){
new GUI();
}//end main
}//end class FocusTraversal02

Listing 1

The GUI class

Listing 2 shows the beginning of the GUI class, including the declaration of several instance variables.  The purpose of these instance variables will be become clear as the discussion progresses.

class GUI extends JFrame{
JLabel labelA = new JLabel(" A ");
JLabel labelB = new JLabel(" B ");
JLabel labelC = new JLabel(" C ");
JPanel panel = new JPanel();
JButton button12 = new JButton("12");
JButton button03 = new JButton("03");
JButton button06 = new JButton("06");
JButton button09 = new JButton("09");
JFrame frame = this;

Listing 2

The constructor

Listing 3 shows the beginning of the constructor for the GUI class.

  public GUI(){//constructor
setSize(250,100);
setTitle("Copyright 2003, R.G.Baldwin");
setDefaultCloseOperation(
JFrame.EXIT_ON_CLOSE);

getContentPane().add(button12,"North");
getContentPane().add(button03,"East");
getContentPane().add(button06,"South");
getContentPane().add(button09,"West");
panel.add(labelA);
panel.add(labelB);
panel.add(labelC);
getContentPane().add(panel);

Listing 3

All of the code in Listing 3 is straightforward, so I won't discuss it further.  If you are unfamiliar with this code, see the other lessons on my web site.

The focus traversal policy

Listing 4 shows an abbreviated version of an inner class from which a FocusTraversalPolicy object will be instantiated to control the focus traversal policy for the frame. (You can view this class definition in its entirety in Listing 12 near the end of this lesson.)

    class TrvslPolicy
extends FocusTraversalPolicy{

//code deleted for brevity

}//end TrvslPolicy

Listing 4

I discussed a class very similar to this one in the lesson entitled entitled Focus Traversal Policies in Java Version 1.4, so I won't discuss this class further in this lesson.

A focus traversal policy based on this class causes the focus to traverse the buttons in Figure 1 in a clockwise manner.

Set the focus traversal policy

Continuing with the constructor, the code in Listing 5 uses the inner class defined above to establish the focus traversal policy for the frame.  The code in Listing 5 also makes the frame visible.
 
    final TrvslPolicy policy = new TrvslPolicy();
frame.setFocusTraversalPolicy(policy);

frame.setVisible(true);

Listing 5

Now for the new and interesting material

The next several code fragments will register mouse listeners on the labels showing A, B, and C in the center of Figure 1, to provide the programmatic focus traversal behavior described earlier.

A mouse listener on the label with an A

The code in Listing 6 uses an anonymous inner class to define, instantiate, and register a mouse listener on the label showing the A in the center of the frame in Figure 1.

    labelA.addMouseListener(
new MouseAdapter(){
public void mousePressed(MouseEvent e){
int shift = e.getModifiersEx() &
InputEvent.SHIFT_DOWN_MASK;

Listing 6

The purpose of this mouse listener is to replicate the focus traversal behavior of the TAB key when the user clicks on the A. 

(Recall that the focus traversal behavior of the TAB key depends or whether or not the user is holding down the Shift key when the TAB key is pressed.)

Get the Shift key state

Listing 6 shows the beginning of the definition of the mousePressed event handler method.  The code in Listing 6 gets and saves an int value that can be used to determine if the Shift key was being held down when the user clicked the label with the A.

(If the Shift key was not being held down, the value of shift in Listing 6 will be zero.  If the Shift key was being held down, the value of shift will not be zero.)

Focus next component

If the Shift key was not being held down, the code in Listing 7 causes the focus to move to the next component (relative to the current focus owner) as specified by the focus traversal policy.

(This replicates the behavior of pressing the TAB key without holding down the Shift key.)

          if(shift == 0){
KeyboardFocusManager.
getCurrentKeyboardFocusManager().
focusNextComponent();

Listing 7

The focusNextComponent method

This is accomplished by invoking the focusNextComponent method of the KeyboardFocusManager class.  However, there is a little more to it than that.  This is not a static method.  Therefore, it is necessary to get access to the KeyboardFocusManager object currently in effect.

What is the KeyboardFocusManager?

Here is part of what Sun has to say about the KeyboardFocusManager class.

"The KeyboardFocusManager is responsible for managing the active and focused Windows, and the current focus owner. The focus owner is defined as the Component in an application that will typically receive all KeyEvents generated by the user. ...

The KeyboardFocusManager is both a centralized location for client code to query for the focus owner and initiate focus changes, and an event dispatcher for all FocusEvents, WindowEvents related to focus, and KeyEvents."

KeyboardFocusManager is an abstract class

You cannot instantiate an object of the KeyboardFocusManager class because it is abstract.  You probably wouldn't want to anyway, because you wouldn't know how to assign the responsibilities described in the above quotation to the new object.

The getCurrentKeyboardFocusManager method

However, the KeyboardFocusManager class provides a static method named getCurrentKeyboardFocusManager, which, according to Sun,

"Returns the current KeyboardFocusManager instance for the calling thread's context."

Focus next component

As you can see in Listing 7, this is what we need in order to invoke the focusNextComponent method and move the focus to the next component specified by the focus traversal policy.

Focus previous component

Listing 8 shows the else clause of the if-else statement that was begun in Listing 7.

          }else{
KeyboardFocusManager.
getCurrentKeyboardFocusManager().
focusPreviousComponent();
}//end else
}//end mousePressed
}//end new MouseAdapter
);//end addMouseListener

Listing 8

The code in Listing 8 is executed if the user was holding down the Shift key when the label with the A was clicked.

In this case, the method named focusPreviousComponent is invoked on the current keyboard focus manager.  This causes the focus to move to the component that appears before the current focus owner in the focus traversal policy.

Again, this replicates the focus traversal behavior of holding down the Shift key and pressing the TAB key.

The requestFocus method

Java has had a method named requestFocus since long before the release of V1.4.  However, here is part of what Sun has to say about that method in the documentation for V1.4.

"Requests that this Component get the input focus, and that this Component's top-level ancestor become the focused Window. ...

Because the focus behavior of this method is platform-dependent, developers are strongly encouraged to use requestFocusInWindow when possible."

The requestFocusInWindow method

Here is part of what Sun has to say about the requestFocusInWindow method.

"Requests that this Component get the input focus, if this Component's top-level ancestor is already the focused Window. ...

The focus behavior of this method can be implemented uniformly across platforms, and thus developers are strongly encouraged to use this method over requestFocus when possible."

Request focus on the button with the 12

The code in Listing 9 registers a mouse listener on the label showing the B.  The purpose of this listener is to move the focus to the button in the twelve o'clock position in Figure 1 whenever the user clicks on the label with the B.

    labelB.addMouseListener(
new MouseAdapter(){
public void mousePressed(MouseEvent e){
button12.requestFocusInWindow();
}//end mousePressed
}//end new MouseAdapter
);//end addMouseListener

Listing 9

As you can see, the change in focus is accomplished by invoking the requestFocusInWindow method on that button's reference whenever the mousePressed event handler method is executed.

Focus relative to a specified component

In addition to providing programmatic focus traversal relative to the current focus owner, V1.4 also provides programmatic focus traversal relative to a specified component, as though that component were the current focus owner.

This is accomplished by invoking the following methods of the KeyboardFocusManager class and specifying a component as a parameter to the method.

These methods differ from the methods used in Listings 7 and 8 in that each of these methods accepts a reference to a component as an incoming parameter.

Each of these methods initiates the traversal operation with the specified component rather than with the current focus owner. The traversal occurs as though the specified component is the current focus owner.  However, the specified component need not be the current focus owner.

An alternative approach

The following alternate but equivalent methods are defined in the Component class.

As with the methods of the KeyboardFocusManager class, each of these methods initiates the traversal operation as though the component on which the method is invoked is the focus owner.  Again, it is not necessary that the component be the focus owner.

As you will see in the upcoming fragments, these two methods require a little less typing than the equivalent versions discussed above.

Focus relative to the label with the C

Listing 10 registers a mouse listener on the label with the C in the center of the frame in Figure 1.  This event handler initiates a focus traversal operation relative to the button in the twelve o'clock position in Figure 1, regardless of the current focus owner.

(The code in Listing 12 also shows the alternative, but equivalent method that can be used to accomplish the focus traversal.)

    labelC.addMouseListener(
new MouseAdapter(){
public void mousePressed(MouseEvent e){
int shift = e.getModifiersEx() &
InputEvent.SHIFT_DOWN_MASK;
if(shift == 0){
KeyboardFocusManager.
getCurrentKeyboardFocusManager().
focusNextComponent(button12);
//This is an alternative method
// button12.transferFocus(); Listing 10

Shift key not being held down

The code in Listing 10 is executed whenever the user clicks on the label with the C while not holding down the Shift key.  This code invokes the focusNextComponent(Component) method of the KeyboardFocusManager class, passing a reference to the button in the twelve o'clock position as a parameter.

This causes the focus to move to the next component following that button in the focus traversal policy (the button at the three o'clock position in Figure 1).

The alternative method

The alternative method for accomplishing the same thing is shown by the last line in Listing 10, which has been turned into a comment.  Note that the alternative method requires considerably less typing than the method that was actually used in Listing 10.

Shift key being held down

Listing 11 shows the code that is executed if the Shift key is being held down when the user clicks the label with the C in the center of the frame in Figure 1.
 
          }else{
//This is an alternative method
// KeyboardFocusManager.
// getCurrentKeyboardFocusManager().
// focusPreviousComponent(button12);
button12.transferFocusBackward(); }//end else }//end mousePressed }//end new MouseAdapter );//end addMouseListener }//end constructor }//end GUI Listing 11

Both alternative methods are shown

Again, both of the alternative methods are shown in Listing 11.  In this case, however the simpler method from the Component class is used, and the method from the KeyboardFocusManager class is turned into a comment.

In this case, the transferFocusBackward method is invoked on the reference to the button at the twelve o'clock position in Figure 1.  This causes the button immediately before the button at the twelve o'clock position in the focus traversal policy (the button in the nine o'clock position in Figure 1) to gain the focus. 

End of constructor and class

The code in Listing 11 also signals the end of the constructor and the end of the definition of the class named GUI.

Run the Program

If you haven't already done so, I encourage you to copy the code from Listing 12 into your text editor, compile it, and execute it.  Experiment with it, pressing buttons and keys, and observing the results of your actions.

Remember, however, that you must be running Java version 1.4 or later to compile and execute this program.

Summary

In this lesson, I have taught you three different ways to implement programmatic focus traversal in Java V1.4 or later.

What's Next?

Future lessons will discuss new focus features of version 1.4 including the following:

Complete Program Listing

A complete listing of the program discussed in this lesson is shown in Listing 12.
 
/*File FocusTraversal02.java
Copyright 2003 R.G.Baldwin

This program illustrates programmatic focus
traversal and control.

The behavior of this program is as follows:

A single JFrame object appears on the screen.
Four JButton objects appear at the North, South,
East, and West locations in the frame. The
buttons display the captions 03, 06, 09, and 12.
(The positions of the buttons with their captions
mimic four of the numbers on a clock.)

Three JLabel objects with labels A, B, and C
appear in the center of the frame.

When the program first starts running, the
button with the caption 12 has the focus.

Successively pressing the TAB key causes the
focus to traverse the buttons in a clockwise
direction: 12, 03, 06, 09 and back to 12.

Holding down the Shift key and successively
pressing the TAB key causes the focus to traverse
the buttons in a counter-clockwise direction:
12, 09, 06, 03, and back to 12.

The above results illustrate the use of a custom
focus traversal policy.

Successively clicking the label with the A causes
the same result as successively pressing the TAB
key.

Holding down the Shift key and successively
clicking the label with the A causes the same
result as holding down the Shift key and
successively pressing the TAB key.

In other words, the result of clicking the label
with the letter A replicates the pressing of the
TAB key. This illustrates programmatic focus
traversal.

Clicking the label with the letter B causes the
button with the 12 to gain the focus.

Clicking the label with the letter C causes the
next component following the button with the 12
in the focus traversal policy (the button with
the 03) to gain the focus.

Holding down the Shift key and clicking the label
with the letter C causes the previous component
before the button with the 12 in the focus
traversal policy (the button with the 09) to gain
the focus.

In other words, clicking the label with the C
causes the same behavior that would occur from
pressing the TAB key when the button with the 12
has the focus.

Requires SDK V1.4 or later. Tested using
SDK 1.4.1 under WinXP
************************************************/

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class FocusTraversal02 {
public static void main(String[] args){
new GUI();
}//end main
}//end class FocusTraversal02
//---------------------------------------------//

class GUI extends JFrame{
JLabel labelA = new JLabel(" A ");
JLabel labelB = new JLabel(" B ");
JLabel labelC = new JLabel(" C ");
JPanel panel = new JPanel();
JButton button12 = new JButton("12");
JButton button03 = new JButton("03");
JButton button06 = new JButton("06");
JButton button09 = new JButton("09");
JFrame frame = this;

public GUI(){//constructor
setSize(250,100);
setTitle("Copyright 2003, R.G.Baldwin");
setDefaultCloseOperation(
JFrame.EXIT_ON_CLOSE);

getContentPane().add(button12,"North");
getContentPane().add(button03,"East");
getContentPane().add(button06,"South");
getContentPane().add(button09,"West");
panel.add(labelA);
panel.add(labelB);
panel.add(labelC);
getContentPane().add(panel);

//Inner class for traversal policy
class TrvslPolicy
extends FocusTraversalPolicy{

public Component getDefaultComponent(
Container focusCycleRoot){
return button12;
}//end getDefaultComponent
//---------------------------------------//

public Component getFirstComponent(
Container focusCycleRoot){
return button09;
}//end getFirstComponent
//---------------------------------------//

public Component getLastComponent(
Container focusCycleRoot){
return button06;
}//end getLastComponent
//---------------------------------------//

public Component getComponentAfter(
Container focusCycleRoot,
Component aComponent){
if(aComponent == button12){
return button03;
}else if(aComponent == button03){
return button06;
}else if(aComponent == button06){
return button09;
}else if(aComponent == button09){
return button12;
}//end else
return button12;//make compiler happy
}//end getComponentAfter
//---------------------------------------//

public Component getComponentBefore(
Container focusCycleRoot,
Component aComponent){
if(aComponent == button12){
return button09;
}else if(aComponent == button09){
return button06;
}else if(aComponent == button06){
return button03;
}else if(aComponent == button03){
return button12;
}//end else
return button12;//make compiler happy
}//end getComponentBefore

}//end TrvslPolicy
//=========================================//

//Local variables must be final for access
// within inner class
final TrvslPolicy policy = new TrvslPolicy();

//Set startup traversal policy
frame.setFocusTraversalPolicy(policy);
frame.setVisible(true);

//Register mouse listeners on the JLabels
labelA.addMouseListener(
new MouseAdapter(){
public void mousePressed(MouseEvent e){
//Replicates focus traversal behavior
// of the TAB key
int shift = e.getModifiersEx() &
InputEvent.SHIFT_DOWN_MASK;
if(shift == 0){
KeyboardFocusManager.
getCurrentKeyboardFocusManager().
focusNextComponent();
}else{
KeyboardFocusManager.
getCurrentKeyboardFocusManager().
focusPreviousComponent();
}//end else
}//end mousePressed
}//end new MouseAdapter
);//end addMouseListener

labelB.addMouseListener(
new MouseAdapter(){
public void mousePressed(MouseEvent e){
//Move focus to button12
button12.requestFocusInWindow();
}//end mousePressed
}//end new MouseAdapter
);//end addMouseListener

labelC.addMouseListener(
new MouseAdapter(){
public void mousePressed(MouseEvent e){
//Focuses relative to button12.
// Illustrates alternative methods for
// accomplishing same purpose.
int shift = e.getModifiersEx() &
InputEvent.SHIFT_DOWN_MASK;
if(shift == 0){
KeyboardFocusManager.
getCurrentKeyboardFocusManager().
focusNextComponent(button12);
//This is an alternative method
// button12.transferFocus();
}else{
//This is an alternative method
// KeyboardFocusManager.
// getCurrentKeyboardFocusManager().
// focusPreviousComponent(button12);
button12.transferFocusBackward();
}//end else
}//end mousePressed
}//end new MouseAdapter
);//end addMouseListener

}//end constructor
}//end GUI

Listing 12

Copyright 2003, Richard G. Baldwin.  Reproduction in whole or in part in any form or medium without express written permission from Richard Baldwin is prohibited.

About the author

Richard Baldwin is a college professor (at Austin Community College in Austin, TX) and private consultant whose primary focus is a combination of Java, C#, and XML. In addition to the many platform and/or language independent benefits of Java and C# applications, he believes that a combination of Java, C#, and XML will become the primary driving force in the delivery of structured information on the Web.

Richard has participated in numerous consulting projects, and he frequently provides onsite training at the high-tech companies located in and around Austin, Texas.  He is the author of Baldwin's Programming Tutorials, which has gained a worldwide following among experienced and aspiring programmers. He has also published articles in JavaPro magazine.

Richard holds an MSEE degree from Southern Methodist University and has many years of experience in the application of computer technology to real-world problems.

Baldwin@DickBaldwin.com

-end-