Focusability in Java Version 1.4

Baldwin shows you how to control the focusability of individual components at runtime, how to query for the currently focused Component, the default Focus Traversal Policy for Swing, and how to use the OS look and feel with Swing.

Published:  June 3, 2003
By Richard G. Baldwin

Java Programming Notes # 1844


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 is the second lesson in a new miniseries that will teach you how to use the features of the new focus subsystem.  The first lesson in the series was entitled Focus Traversal Policies in Java Version 1.4.

During the lifetime of Java, 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."

Unfortunately, Sun also states,

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

KeyboardFocusManager

The KeyboardFocusManager class provides APIs that make it possible for client code to:

I will be discussing each of these capabilities in the tutorial lessons in this miniseries.  In addition, I will use the KeyboardFocusManager class in the sample program in this lesson.

PropertyChangeListener

Clients can inquire about the focus state directly.  Alternatively, clients can register a PropertyChangeListener to receive a PropertyChangeEvent when a change to the focus state occurs.

I will also discuss these alternatives in the tutorial lessons in this miniseries.

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 several aspects of the new focus subsystem, including:

In addition, this lesson will show you how to write Swing programs that exhibit the look and feel of the operating system being used.  While this is not directly related to the new focus subsystem, it is good thing to know, and this is an opportune time for me to explain it.

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.

Information from the previous lesson

The first lesson in this series, entitled Focus Traversal Policies in Java Version 1.4, contained a great deal of important information, including descriptions of several important terms:

In addition, that lesson showed you how to establish a focus traversal policy, and how to modify that policy at runtime.

It is strongly recommended that you study that lesson before continuing with this lesson.

Preview

The sample program that I will discuss in this lesson illustrates the following:

Discussion and Sample Code

Description of the program named Focusability01

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

Figure 1  The GUI at startup

Three JButton objects and a JTextField object appear at the North, South, East, and Center locations in the frame.

Program state at startup

When the program first starts running, the text field has the focus and the button in the South location displays the word Focusable.

The focus traversal policy

The default focus traversal policy is in effect at startup (and throughout the running of the program).  Generally, this policy causes the focus to traverse from left to right, top to bottom (I will discuss this in more detail later).

Successive presses on the tab key causes the focus to traverse these components in the following order:

Change focusability of the South button

When you click Button2, the text and the color of the characters in the South button changes to that shown in Figure 2.

Figure 2  The GUI after clicking Button2

More importantly, the South button loses its ability to gain the focus when you click Button2.

The new focus traversal path

Successive presses on the tab key causes the focus to traverse these components in the following order (skipping the South button):

Toggle the focusability of the South button

Successive clicking on Button2 causes the South button to toggle back and forth between being focusable and not being focusable.

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

More detailed description of the program

The GUI uses Swing components and exhibits a look and feel that is the standard look and feel for the operating system under which the program is running.

The program displays a frame object containing a button at the South location of the frame, which is initially labeled Focusable.  When this button is labeled Focusable, it is part of the default focus traversal path, which proceeds from the top left to the bottom right in the GUI.

The focus traversal path

The previous lesson taught you how to establish the focus traversal path for a graphical user interface.  If you don't explicitly establish the traversal path, a default focus traversal path will be used.

The default focus traversal path for Swing components

The default traversal path is not the same for AWT components and Swing components.  Here is what Sun has to say about the default traversal path for Swing components:

"Swing applications, or mixed Swing/AWT applications, that use one of the standard look and feels, or any other look and feel derived from BasicLookAndFeel, will use LayoutFocusTraversalPolicy for all Containers by default."

The LayoutFocusTraversalPolicy

Here is part of what Sun has to say about the LayoutFocusTraversalPolicy:

"... Based on their size and position, Components are roughly categorized into rows and columns. For a Container with horizontal orientation, columns run left-to-right or right-to-left, and rows run top-to-bottom. ... All columns in a row are fully traversed before proceeding to the next row."

I did not explicitly define a focus traversal path for this program, so the default focus traversal policy is in effect throughout the running of this program.

The above quotation from Sun is a little cryptic, buy you should be able to pick out enough information to understand why the default traversal path for this program runs from left to right, top to bottom.

Toggling the focusability of the South button

The GUI also displays a button labeled Button2, as shown in Figure 1.  Clicking this button toggles the text on the South button between Focusable and Not Focusable.

When the South button is labeled Not Focusable, the South button cannot receive the focus.  It is not included in the focus traversal path.  It does not receive the focus as a result of successively pressing the tab key, and it does not receive the focus when it is clicked with the mouse.

Not disabled for events

However, each time the South button is clicked with the mouse, regardless of whether it has or gets the focus, it fires an ActionEvent.

(Not being focusable does not equate to being unable to fire events.)

Also, if the space bar is pressed while the South button has the focus, it fires an ActionEvent.

The ActionEvent handler

The ActionEvent handler registered on the South button causes the text "Button0 clicked" followed by the name of the "Currently Focused Component" to be displayed.  Here is an example of such an output produced by clicking the South button while Button2 has the focus and the South button is not focusable:

Button0 clicked
Currently Focused Component: Button2

Other components

In addition to the two buttons discussed above, the GUI also displays a text field and another button as shown in Figure 1.  No listeners are registered on either of those components.

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

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{
  JTextField textField;
  JButton button0;
  JButton button1;
  JButton button2;
  boolean button0isFocusable = true;

Listing 2

The class begins by declaring reference variables that will be used to hold references to each of the components shown in Figure 1.

The code in Listing 2 also declares and initializes an instance variable that will be used to hold the focusability state of the South button.  When this variable is true, the button is focusable.  When this variable is false, the button is not focusable.

The constructor

The constructor for the GUI class begins in Listing 3. 
 
  public GUI(){//constructor
    textField = new JTextField("Some text");
    button0 = new JButton("Focusable");
    button1 = new JButton("Button1");
    button2 = new JButton("Button2");

Listing 3

The code in Listing 3 instantiates the four components shown in Figure 1, and saves those object's references in the corresponding instance variables.

Give each component a name

Later on, a query will be performed to determine which component currently has the focus.  The name of the currently focused component will be displayed on the standard output device.

The code in Listing 4 sets the name property for each of the four components to a unique value.

    textField.setName("Text Field");
    button0.setName("Button0");
    button1.setName("Button1");
    button2.setName("Button2");

Listing 4

The worst problem

Sun provides several reasons for releasing a new focus subsystem in V1.4, in order to correct problems with the earlier focus subsystem.

According to Sun,

"The single worst problem with the earlier AWT focus implementation was the inability to query for the currently focused Component."

Code in the next fragment demonstrates that this problem has been solved in V1.4.

An action listener on the South button

Continuing with the code in the constructor, the code in Listing 5 registers an action listener on the South button.  The purpose of this action listener is twofold:

    button0.addActionListener(
                            new ActionListener(){
      public void actionPerformed(ActionEvent e){
        System.out.println("Button0 clicked");

        System.out.println(
                "Currently Focused Component: " +
                KeyboardFocusManager.
                getCurrentKeyboardFocusManager().
                getFocusOwner().getName());
      }//end actionPerformed
    });

Listing 5

Two print statements

The code in Listing 5 contains two print statements inside the actionPerformed method.  The first print statement simply displays the fact that the South button was clicked.

The second print statement gets and displays the value of the name property (set earlier) of the component that holds the focus when the South button is clicked.

Toggle the focusability of the South button

Whether or not a component can gain the focus is determined by the value of the focusable property of the component.  The code in Listing 6 registers an action listener on button2, which toggles the focusability of the South button between true and false each time button2 is clicked.

    button2.addActionListener(
                            new ActionListener(){
      public void actionPerformed(ActionEvent e){
        if(button0isFocusable){
          button0isFocusable = false;
          button0.setForeground(Color.RED);
          button0.setText("Not Focusable");
          button0.setFocusable(false);
        }else{
          button0isFocusable = true;
          button0.setForeground(Color.BLACK);
          button0.setText("Focusable");
          button0.setFocusable(true);
        }//end else
      }//end actionPerformed
    });

Listing 6

Focusable

When the value of the focusable property is set to true, the South button is included in the focus traversal path, and also gains the focus when it is clicked by the mouse.

Not focusable

When the value of the focusable property is set to false, the South button is unable to gain the focus.  It is removed from the focus traversal path, and also doesn't gain the focus when clicked by the mouse.

Finish constructing the GUI

The code in Listing 7 sets the size and the title of the frame.
 
    setSize(250,120);
    setTitle("Copyright 2003 R.G.Baldwin");

    //Add objects to the frame using default
    // border layout manager.  Do not add in same
    // order as default focus traversal order.
    getContentPane().add(button0,"South");
    getContentPane().add(textField,"North");
    getContentPane().add(button1,"East");
    getContentPane().add(button2,"Center");

Listing 7

In addition, the code in Listing 7 adds the four components to the frame.

Note the addition order of the components

Note that the components were purposely added to the frame in an order that is different from the default focus traversal path.  This demonstrates that under the new focus subsystem, the default focus traversal path for Swing components is independent of the order in which the components are added to the container.

Set the look and feel

If you don't set the look and feel when you create a Swing GUI, the default look and feel will be the look and feel sometimes known as the metal look and feel or the Java look and feel.

That may not be what you want.  You may want the look and feel to match the native look and feel for the current operating system.
 
    String plafClassName =
       UIManager.getSystemLookAndFeelClassName();

    try{
       UIManager.setLookAndFeel(plafClassName);
    }catch(Exception ex){System.out.println(ex);}

    //Cause the L&F to become visible.
    SwingUtilities.updateComponentTreeUI(this);

Listing 8

Get and use look and feel for current operating system

The code in Listing 8 gets and uses the look and feel for the current operating system without a requirement for the programmer to know the current operating system (provided that Java supports a look and feel for that operating system).

Odds and ends

The code in Listing 9 takes care of a couple more odds and ends, closes the constructor, and closes the definition of the GUI class.

    setVisible(true);//make the frame visible
    setDefaultCloseOperation(
                           JFrame.EXIT_ON_CLOSE);
  }//end constructor
}//end class GUI definition

Listing 9

Run the Program

I encourage you to copy the code from Listing 10 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, because it makes use of Java features that were first released in V1.4.

Summary

In this lesson, I have taught you:

What's Next?

As time goes on, I plan to publish additional lessons that will help you learn to use other features of the new focus subsystem.  Future lessons will discuss new focus features of version 1.4 including:

Complete Program Listing

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

This program illustrates:
1. How to control focusability at runtime.
2. The ability to query for the currently
   focused Component.
3. Default Focus Traversal Policy
4. Use of the OS look and feel with Swing.

The behavior of the program is as follows:

The GUI uses Swing components and exhibits a
look and feel that is the standard look and feel
for the operating system under which the program
is running.

The program displays a frame object containing a
button at the bottom of the frame, which is
initially labeled Focusable.  While this button
is labeled Focusable, it is part of the default
focus traversal path, which proceeds from the
top left to the bottom right in the GUI.

The GUI also displays a button labeled button2.
Clicking this button toggles the text on the
bottom button between Focusable and
Not Focusable.  When the bottom button is labeled
Not Focusable, the bottom button does not receive
the focus.  It is not included in the focus
traversal path, and it does not receive the focus
when it is clicked with the mouse.  However, each
time it is clicked with the mouse, regardless of
whether or not it has or gets the focus, it fires
an ActionEvent, which causes the text
"Button0 clicked" followed by the name of the
"Currently Focused Component "to be displayed on
the Standard Output Device.

In addition to the two buttons discussed above,
the GUI also displays a text field and another
button.  No active listeners are registered on
either of these components.

Requires Java SDK V1.4 or later.
Tested using JDK 1.4 under WinXP
************************************************/

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

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

//=============================================//

class GUI extends JFrame{
  JTextField textField;
  JButton button0;
  JButton button1;
  JButton button2;
  boolean button0isFocusable = true;

  public GUI(){//constructor
    //Create several visual components
    textField = new JTextField("Some text");
    button0 = new JButton("Focusable");
    button1 = new JButton("Button1");
    button2 = new JButton("Button2");

    textField.setName("Text Field");
    button0.setName("Button0");
    button1.setName("Button1");
    button2.setName("Button2");

    //Register an action listener on button0 to
    // show that button0 fires action events even
    // when it is not focusable.
    button0.addActionListener(
                            new ActionListener(){
      public void actionPerformed(ActionEvent e){
        System.out.println("Button0 clicked");
        //According to Sun,  The single worst
        // problem with the earlier AWT focus
        // implementation was the inability to
        // query for the currently focused
        // Component.  The following statement
        // demonstrates that the problem has
        // been solved in V1.4.
        System.out.println(
                "Currently Focused Component: " +
                KeyboardFocusManager.
                getCurrentKeyboardFocusManager().
                getFocusOwner().getName());
      }//end actionPerformed
    });

    //Register an action listener on button2 to
    // toggle focusability of button0.
    button2.addActionListener(
                            new ActionListener(){
      public void actionPerformed(ActionEvent e){
        if(button0isFocusable){
          button0isFocusable = false;
          button0.setForeground(Color.RED);
          button0.setText("Not Focusable");
          button0.setFocusable(false);
        }else{
          button0isFocusable = true;
          button0.setForeground(Color.BLACK);
          button0.setText("Focusable");
          button0.setFocusable(true);
        }//end else
      }//end actionPerformed
    });

    setSize(250,120);
    setTitle("Copyright 2003 R.G.Baldwin");

    //Add objects to the frame using default
    // border layout manager.  Do not add in same
    // order as default focus traversal order.
    getContentPane().add(button0,"South");
    getContentPane().add(textField,"North");
    getContentPane().add(button1,"East");
    getContentPane().add(button2,"Center");

    //Set L&F to op syst being used
    String plafClassName =
       UIManager.getSystemLookAndFeelClassName();

    try{
       UIManager.setLookAndFeel(plafClassName);
    }catch(Exception ex){System.out.println(ex);}

    //Cause the L&F to become visible.
    SwingUtilities.updateComponentTreeUI(this);
    setVisible(true);//make the frame visible
    setDefaultCloseOperation(
                           JFrame.EXIT_ON_CLOSE);
  }//end constructor

}//end class GUI definition
//=============================================//

Listing 10


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-