Java Programmatic Focus Traversal in Java V1.4

Programmatic Focus Traversal in Java V1.4

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:

  • Defining new focus traversal keys
  • How to control focusability at runtime.
  • The ability to query for the currently focused Component.
  • The default Focus Traversal Policy.
  • How to establish a focus traversal policy and modify it at
    runtime.

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.

  • focusNextComponent(Component)
  • focusPreviousComponent(Component)

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.

  • transferFocus()
  • transferFocusBackward()

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:

  • The KeyEventDispatcher interface
  • The KeyEventPostProcessor interface
  • FocusEvent and WindowEvent
  • Event delivery
  • Opposite components
  • Temporary focus events
  • Focus and PropertyChangeListener
  • Focus and VetoableChangeListener

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.

[email protected]

-end-

Latest Posts

Related Stories