JavaFocus Traversal Policies in Java Version 1.4

Focus Traversal Policies in Java Version 1.4

Java Programming Notes # 1840


Preface

New features in SDK Version 1.4.0

JavaTM 2 SDK, Standard Edition V1.4 contains a
large number of new features, including a completely new focus subsystem.

I became hooked
on Java in April 1996.  Since then, Java has progressed from V1.0 up to
V1.4.  Fortunately, during that period, few if any of the improvements
included in new versions have been incompatible with code written for previous
versions.  Unfortunately, that history of upgrade success changed with the
release of the new focus subsystem in V1.4.  Several aspects of the new
subsystem are incompatible with code written for previous versions.

Historical problems with the focus subsystem

According
to Sun,

"Prior to Java 2 Standard Edition, JDK 1.4, the AWT focus subsystem
was inadequate. It suffered from major design and API problems,
as well as over a hundred open bugs. Many of these bugs were caused by
platform inconsistencies, or incompatibilities between the native
focus system for heavyweights and the Java focus system for
lightweights."

What does Sun say about focus in V1.4?

Sun goes on to describe some of the specific problems and then states:

"To address these and other deficiencies, we have designed a new focus
model for the AWT in JDK 1.4. The primary design changes were the
construction of a new centralized KeyboardFocusManager class, and a
lightweight focus architecture. The amount of focus-related,
platform-dependent code has been minimized and replaced by fully
pluggable and extensible public APIs in the AWT. While we have
attempted to remain backward compatible with the existing
implementation, we were forced to make minor incompatible changes in
order to reach an elegant and workable conclusion. We anticipate that
these incompatibilities will have only a trivial impact on existing
applications."

A lot to learn

There is a lot to learn
about the new focus subsystem.  It is anything but trivial.  This lesson
will deal with only one aspect of the new subsystem, and will deal with that
aspect from
a relatively simple viewpoint.  This lesson deals with focus traversal
among the components in a single-level container.

(In this lesson, there are no containers that contain focusable components within that
single container.  Thus, I refer to it as a single-level container. 
In particular, there is no requirement to deal with the complexities of having the focus move
from one container up or down a level to a parent or child container, known as
up cycle and down cycle.)

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.


General Background Information

Focusability

A focusable Component is a component that can become the focus owner and
participates in keyboard focus traversal with
a FocusTraversalPolicy.

Focus traversal

Since focus traversal is the primary topic of this lesson, we should probably
begin with a description of that term.  Here is how Sun describes focus
traversal
:

"Focus traversal — the user’s ability to change the “focus
owner
” without moving the cursor. Typically, this is done using
the keyboard (for example, by using the TAB key), or an
equivalent device in an accessible environment. Client code can
also initiate traversal programmatically. Normal focus traversal
can be either “forward” to the “next” Component, or “backward” to
the “previous” Component."

I imagine that everyone reading this lesson is familiar with the focus
traversal
process
described above.

The focus cycle root

Focus traversal is governed by a focus traversal policy.  Before getting into a discussion of the focus traversal policy,
however, I need to
introduce the concept of a focus cycle root along with some other related
terms.

According to Sun,

Focus cycle root — Container that is the root of the Component
hierarchy for a particular "focus traversal cycle". When the
"focus owner" is a Component inside a particular cycle, normal
forward and backward focus traversal cannot move the “focus owner” above the focus cycle root in the Component hierarchy.
Instead, two additional traversal operations, “up cycle” and
down cycle“, are defined to allow keyboard and programmatic
navigation up and down the focus traversal cycle hierarchy."

Focus traversal cycle

Sun has this to
say about the focus traversal cycle.

"Focus traversal cycle — a portion of the Component hierarchy,
such that normal focus traversal "forward" (or "backward") will traverse through
all of the Components in the focus cycle, but no other Components. This cycle
provides a mapping from an arbitrary Component in the cycle to its "next"
(forward traversal) and "previous" (backward traversal) Components."

Focus owner

According to Sun, the focus owner
is the Component that typically receives
keyboard input.

Up cycle and down cycle
traversal operations

I will deal with up cycle and down
cycle
traversal operations in a subsequent lesson.


Focus traversal policy

And finally, here is how Sun describes a
FocusTraversalPolicy.

"A FocusTraversalPolicy
defines the order in which Components with a particular focus cycle root are
traversed.
"

I will show you how to establish and use a focus traversal policy in the
sample program to be discussed later in this lesson.


Primary responsibility of a FocusTraversalPolicy

The primary
responsibility of a FocusTraversalPolicy is to specify the next
and previous Components to gain focus when traversing forward or backward in a
user interface.  Within a list of focusable components, this involves
specifying the components to receive focus after and before the currently
focused component.

Focus traversal wraparound

In order to support wraparound at each end of a list of focusable components,
each FocusTraversalPolicy must also specify the first and last
Components in a traversal cycle.  According to Sun, these are the components that receive
focus when the traversal wraps around the end of the list going in either
direction. 

The first
Component is the Component that receives the focus when traversal wraps in the
forward direction.  The last Component is the Component that
receives the focus when traversal wraps in the reverse direction.

(Note that I will
raise, but will not answer, some interesting questions regarding the wraparound
later.)

A default component and an initial component

The FocusTraversalPolicy must also specify a default Component,
which is the first component to receive the focus when traversing down into a
new focus traversal cycle.

A FocusTraversalPolicy can optionally
specify an initial Component, which is the first to receive focus when a
Window is first made visible.

(The sample program in this lesson doesn’t specify the optional initial
component.)

Five methods are involved

I will
discuss and explain a sample program that satisfies the requirements listed
above by defining the behavior of the following five methods:

  • getComponentAfter
  • getComponentBefore
  • getFirstComponent
  • getLastComponent
  • getDefaultComponent

(The sample program in this lesson doesn’t make use of the optional
getInitialComponent method.)

Establishing the FocusTraversalPolicy

The FocusTraversalPolicy for a
container is established by invoking the container’s setFocusTraversalPolicy
method and passing a FocusTraversalPolicy object’s reference as a parameter.

If a policy is not
explicitly set on a container, then the container inherits its policy from its nearest
focus-cycle-root ancestor.


Preview

In this lesson, I will show you how to establish a custom focus traversal
policy, and how to modify that policy at runtime.

Discussion
and Sample Code

The program named FocusTraversal01

This program illustrates the new
FocusTraversalPolicy that was released in Java SDK Version 1.4.

Description of the program

A single JFrame object appears on the screen,
as shown in Figure 1.

Figure 1  The GUI at startup

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.)

When the program first starts running, the button with the caption 12 has the focus, and the number sequence 09,03,12,06,09,… appears near the center of the frame.

Click to change the sequence

When you click on that sequence, the sequence changes to 09,06,12,03,09,… and the color of the characters changes to red,
as shown in Figure 2.

Figure 2  The GUI after clicking the sequence

Successive clicking on the sequence causes the sequence to toggle back and forth between the two sequences given above, and causes the color of the characters to toggle between black and red.

Focus traversal in the forward direction

When the
black sequence 09,03,12,06,09,… appears, successively pressing the tab key causes the focus to traverse the four buttons in the order given by the
black sequence.

Similarly, when the red sequence 09,06,12,03,09,… appears,
successively pressing the tab key causes the focus to traverse the four buttons in the order given by
the red sequence.

Focus traversal in the reverse
direction

In both cases, holding down the shift key while pressing the tab key reverses the order of focus traversal.

Focus is well behaved

When you click on
the sequence to change it, the focus does not jump from its current button to a different button.

When you
have clicked on a button, causing that button to have the focus, pressing the tab key
causes the focus to move from that button to the next button defined by the sequence that is showing.

SDK Version 1.4 required

This program requires SDK V1.4 or later, because features used in this program
were first released in V1.4.

The program was tested using SDK 1.4.1 under WinXP

Will discuss sample program in fragments

As usual, I will discuss the program in fragments.  You can view a listing
of the entire program in Listing 13 near the end of the lesson.

The main method

The program begins in Listing 1 where the main method simply
instantiates an object of the class named GUI.
 

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

Listing 1

It is the class named GUI that produces the user interface shown in
Figures 1 and 2.

The class named GUI

The class named GUI, which extends JFrame, begins in Listing
2.
 

class GUI extends JFrame{
  boolean policyIsA = true;
  JLabel seq = new JLabel(
                       "    09,03,12,06,09,...");
  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

Listing 2 instantiates all four of the buttons and the label that you saw in
Figure 1.

(The component in the center of the GUI containing the sequence of numbers
is a JLabel whose reference is stored in a reference variable named
seq
.)

In addition, the code in Listing 2 saves a reference to the GUI object in the
reference variable named frame.  This is used later to gain access
to the GUI object from within some inner classes.

The variable named policyIsA

This switches between
two different focus traversal policies at runtime.  The boolean
variable named policyIsA in Listing 1 is used later to keep track of
which policy is currently in force.

The constructor for the GUI class

The constructor for the GUI class begins in Listing 3.
 

  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");
    getContentPane().add(seq,"Center");

Listing 3

The code in Listing 3 is completely straightforward, so I won’t discuss it
further.

(In case you are unfamiliar with the construction of graphical user
interfaces in Java, I have published numerous tutorial lessons on that topic on
my web site.)

The class named TravPolicyA

Listing 4 shows the beginning of an inner class named TravPolicyA,
which extends the class named FocusTraversalPolicy, and overrides five
of the six methods defined in that class.
 

    class TravPolicyA
                    extends FocusTraversalPolicy{

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

Listing 4

Background information on the FocusTraversalPolicy
class

The FocusTraversalPolicy class is an abstract class,
and five of the six methods defined in the class are declared abstract. 
Therefore, the FocusTraversalPolicy class exists for the sole purpose
of being extended, a task often relegated to interfaces in Java.

However, the class defines one non-abstract method named
getInitialComponent
, so the FocusTraversalPolicy class cannot be
replaced by an interface.  The default implementation of the
getInitialComponent
method returns the default Component.

Overridden methods

The code in Listing 4 overrides the method named getDefaultComponent
Subsequent listings will override the remaining four abstract methods of the
FocusTraversalPolicy
class.

The overridden methods in the FocusTraversalPolicy object must specify the
next component that is to receive the focus whenever focus traversal occurs in a
forward or reverse direction.

The getDefaultComponent method

The code in the overridden getDefaultComponent method in Listing 4 returns a
reference to the button at the 12-o’clock position in the GUI as the default
component.  According to Sun,

"This Component will be the first to receive focus when traversing down
into a new focus traversal cycle rooted at focusCycleRoot."

Because this GUI has only one focus cycle root, this is the component that
receives the focus when the program starts running.

(Note that even though this method receives a reference to the focus cycle
root as an incoming parameter, that information is not used in this program.)

The first component

The overridden method named getFirstComponent in Listing 5 specifies
the first component, as the component in the 9-o’clock position in the
GUI.
 

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

Listing 5

According to Sun,

"This method is used to determine the next Component to focus when
traversal wraps in the forward direction."

The last component

Similarly, the overridden method named getLastComponent in Listing 6
identifies component in the 6-o’clock position as the "Component to focus
when traversal wraps in the reverse direction.
"
 

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

Listing 6

The next component in forward traversal

Listing 7 shows the overridden version of the method named
getComponentAfter
.  This method receives a reference to a component
by the parameter name aComponent.  According to Sun, this method

"Returns the Component that should receive the focus after aComponent."

In this program, this method identifies each component that is to receive
the focus in succession as focus is traversed in the forward direction.
 

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

Listing 7

This method gets called by the focus subsystem, passing the currently focused
component as an input parameter.  The method returns the component that
should be the next component to receive the focus for forward traversal.

A little confusion

The discussion up to this point, based on Sun’s documentation, implies that
the system should know how to traverse from the last component to the
first
component when focus traversal wraps at the end of the traversal
cycle.  This implies that, (based on the specification of the first and
last components earlier),
the system should know how to traverse from
button06
to button09 without being told how to do that in the method
named getComponentAfter.

I’m probably missing something here, but I don’t find that to be the case. 
The only way that I have been able to cause the focus to traverse from
button06
to button09 is to
explicitly include the information that button09 is the component
after
button06 in the overridden version of the getComponentAfter
method.

The next component in reverse traversal

Listing 8 shows the overridden version of the method named
getComponentBefore
.  Again, this method receives an incoming
parameter known locally as aComponent, and according to Sun, this
method

"Returns the Component that should receive the focus before
aComponent
."

In this program, this method identifies each component that is to
receive the focus in succession as focus is traversed in the reverse
direction.
 

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

    }//end TravPolicyA

Listing 8

The method named getComponentBefore is called by the focus subsystem
to learn the order of focus traversal as focus is traversed in the reverse
direction.  This method simply identifies the button in the reverse order
of the method shown in Listing 7.

The end of the class definition

Listing 8 also signals the end of the inner class named TravPolicyA
As you will see later, an object of this class provides the traversal policy
when the black number sequence is showing on the GUI.

The TravPolicyB class

Listing 13 near the end of the lesson includes
an inner class named TravPolicyB.  An object of this class is used
to provide the traversal policy when the red number sequence is showing on the
GUI.

Because of the similarity between this class and the class named TravPolicyA
discussed earlier, I won’t discuss this class in detail.  It differs from
TravPolicyA only in the specified order of focus traversal among the
buttons.

Two FocusTraversalPolicy objects

Recall that we are still discussing code in the constructor for the GUI
class.

The code in Listing 9 instantiates one object from each of the inner
classes named TravPolicyA and TravPolicyB discussed earlier and
saves those object’s references in the final local variables named
policyA
and policyB.
 

    final TravPolicyA policyA =
                               new TravPolicyA();
    final TravPolicyB policyB =
                               new TravPolicyB();

Listing 9

Why are the variables final?

In case you are wondering why these two variables were declared final,
that is a requirement of the compiler.  When policyA is not declared
final, the following compiler error is produced by the javac compiler, V1.4.1:

"local variable policyA is accessed from within inner class; needs to be
declared final"

The inner class that is referred to by this error message is an anonymous
inner class that I will discuss later.  The anonymous inner class is used to register a mouse
listener on the JLabel object.

Set startup traversal policy

The code in Listing 10 sets the startup traversal policy to be governed by
the object earlier instantiated from the class named TravPolicyA
The startup policy is established by invoking the setFocusTraversalPolicy on the JFrame object
when the object is constructed. 
(The code in Listing 10 also causes the GUI to become visible on the
screen.)

 

    frame.setFocusTraversalPolicy(policyA);

    frame.setVisible(true);

Listing 10

The setFocusTraversalPolicy method

Here is part of what Sun has to say about the setFocusTraversalPolicy,
method, which the JFrame class inherits from the Container class.

"Sets the focus traversal policy that will manage keyboard traversal
of this Container’s children, if this Container is a focus cycle root. If
the argument is null, this Container inherits its policy from its focus-
cycle-root ancestor. If the argument is non-null, this policy will be
inherited by all focus-cycle-root children that have no keyboard- traversal
policy of their own (as will, recursively, their focus-cycle- root
children)."

Thus, whenever the setFocusTraversalPolicy method is invoked on the
JFrame
object, (passing a valid FocusTraversalPolicy object’s
reference as a parameter),
that object governs the traversal policy from
that point forward until the method is invoked again passing a different
FocusTraversalPolicy
object’s reference as a parameter.

A mouse listener on the JLabel object

Listing 11 shows the beginning of an anonymous inner class, which is used to
register a mouse listener on the JLabel object that displays the
sequences of numbers.  The beginning of an overridden mousePressed
method is shown in Listing 11.

(Listing 11 shows the if clause of an if-else statement. 
The else clause will be shown in Listing 12.)

    seq.addMouseListener(
      new MouseAdapter(){
        public void mousePressed(MouseEvent e){
          //Switch traversal policy
          if(policyIsA){
            policyIsA = false;
            seq.setText(
                       "    09,06,12,03,09,...");
            seq.setForeground(Color.RED);
            frame.setFocusTraversalPolicy(
                                        policyB);

Listing 11

Toggle between two focus traversal policies

The purpose of the mouse listener is to toggle the focus subsystem between
the two FocusTraversalPolicy objects when the user clicks the JLabel
object in the center of the GUI.

The code in Listing 11 is straightforward, with the operative statement being
the final statement in Listing 11, which invokes the setFocusTraversalPolicy
method on the JFrame to switch the traversal policy object from
policyA
to policyB.

(Some other changes to the displayed sequence of numbers and the color of
the sequence are also made in Listing 11.)

The else clause

The else clause of the if-else statement in the
mousePressed
method is shown in Listing 12.
 

          }else{
            policyIsA = true;
            seq.setText(
                       "    09,03,12,06,09,...");
            seq.setForeground(Color.BLACK);
            frame.setFocusTraversalPolicy(
                                        policyA);
          }//end else

        }//end mousePressed
      }//end new MouseAdapter
    );//end addMouseListener
  }//end constructor
}//end GUI

Listing 12

The code in Listing 12 switches the traversal policy from policyB back to
policyA, changing the displayed sequence of numbers and the color of the
sequence in the process.

That’s a wrap

Finally, the code in Listing 12 ends the definition of the anonymous class,
ends the definition of the constructor, and
ends the definition of the GUI class.

The bottom line

When the user clicks the JLabel in the center of the GUI, an
overridden mousePressed method is executed.  The code in that method
determines which focus traversal policy object is currently governing focus
traversal, and replaces that object with a different focus traversal policy
object.  This makes it possible to change the focus traversal order among
the components at runtime.

Run the Program


I encourage you to copy the code from Listing 13 into your text editor, compile it, and execute it.  Experiment
with it, making changes, and observing the results of your changes.

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

Summary

In this lesson, I have taught you how to establish a custom focus traversal
policy, and how to modify that policy at runtime.

What’s Next?

As time goes on, I plan to publish additional lessons that will help
you learn to use about other features of the new focus subsystem that was
introduced in Java SDK Version 1.4.  Stay tuned for more on this subject.

Complete Program Listing


A complete listing of the program discussed in this lesson is shown in Listing
13 below.

 

/*File FocusTraversal01.java
Copyright 2003 R.G.Baldwin

This program illustrates the new
FocusTraversalPolicy that was released in
SDK V1.4.

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.)

When the program first starts running, the
button with the caption 12 has the focus, and the
number sequence 09,03,12,06,09,... appears near
the center of the frame.

When you click on that sequence, the sequence
changes to 09,06,12,03,09,... and the color of
the characters changes to red to emphasize that
the sequence has changed.

Successive clicking on the sequence causes the
sequence to toggle back and forth between the two
sequences given above, and causes the color of
the characters to toggle between black and red.

When the sequence 09,03,12,06,09,... appears,
successive pressing of the tab key causes the
focus to traverse the four buttons in the order
given by the sequence.

Similarly, when the sequence 09,06,12,03,09,...
appears, successive pressing of the tab key
causes the focus to traverse the four buttons in
the order given by that sequence.

In both cases, holding down the shift key while
pressing the tab key reverses the order of focus
traversal.

When you use the mouse to change the sequence,
the focus does not jump from its current button
to a different button.

When you use the mouse to cause the focus to rest
on a particular button and then press the tab
key, the focus moves from that button to the next
button as defined by the sequence that is showing
in the center of the frame.

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 FocusTraversal01 {
  public static void main(String[] args){
    new GUI();
  }//end main
}//end class FocusTraversal01
//---------------------------------------------//

class GUI extends JFrame{
  boolean policyIsA = true;
  JLabel seq = new JLabel(
                       "    09,03,12,06,09,...");
  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");
    getContentPane().add(seq,"Center");

    //Inner class for traversal policy A
    class TravPolicyA
                    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 button06;
        }else if(aComponent == button03){
          return button12;
        }else if(aComponent == button06){
          return button09;
        }else if(aComponent == button09){
          return button03;
        }//end else
        return button12;//make compiler happy
      }//end getComponentAfter
      //---------------------------------------//

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

    }//end TravPolicyA
    //=========================================//

    //Inner class for traversal policy B
    class TravPolicyB
                    extends FocusTraversalPolicy{

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

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

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

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

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

    }//end TravPolicyB
    //=========================================//

    //Local variables must be final for access
    // within inner class
    final TravPolicyA policyA =
                               new TravPolicyA();
    final TravPolicyB policyB =
                               new TravPolicyB();

    //Set startup traversal policy to Policy A
    frame.setFocusTraversalPolicy(policyA);

    frame.setVisible(true);

    //Register mouse listener on the JLabel
    seq.addMouseListener(
      new MouseAdapter(){
        public void mousePressed(MouseEvent e){
          //Switch traversal policy
          if(policyIsA){
            policyIsA = false;
            seq.setText(
                       "    09,06,12,03,09,...");
            seq.setForeground(Color.RED);
            frame.setFocusTraversalPolicy(
                                        policyB);
          }else{
            policyIsA = true;
            seq.setText(
                       "    09,03,12,06,09,...");
            seq.setForeground(Color.BLACK);
            frame.setFocusTraversalPolicy(
                                        policyA);
          }//end else
        }//end mousePressed
      }//end new MouseAdapter
    );//end addMouseListener
  }//end constructor
}//end GUI

Listing 13

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