Focus Traversal Policies in Java Version 1.4

Baldwin shows you how to establish a focus traversal policy, and how to modify that policy at runtime.

Published:  April 29, 2003
By Richard G. Baldwin

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:

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

Baldwin@DickBaldwin.com

-end-