JavaThe Opposite Focus Component

The Opposite Focus Component

Java Programming, Notes # 1854


Preface

The focus subsystem

When JavaTM 2 SDK, Standard Edition Version 1.4
was released, it contained a large number of new features.  This included many changes and additions to
the focus subsystem. 

Changes to the focus subsystem represented a major departure from previous
versions of Java.  Unfortunately, some of the changes caused Java code that
had compiled and run successfully under previous versions of the SDK to fail
under the new version.

This lesson is part of a series of lessons designed to
teach you how to use the new features of the focus subsystem.

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

Previous topics

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

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

This lesson will show you how to write code to get the opposite focus
component.

Background information

Before getting into the technical details, I will provide some quotations
from Sun that justify this new feature.  In discussing the changes to the
focus subsystem, Sun has this to say:

"… many developers noted that the APIs for FocusEvent and
WindowEvent were insufficient because they did not provide a way for determining
the "opposite" Component involved in the focus or activation change. For
example, when a Component received a FOCUS_LOST event, it had no way of knowing
which Component was gaining focus. Since Microsoft Windows provides this
functionality for free, developers migrating from Microsoft Windows C/C++ or
Visual Basic to Java had been frustrated by the omission."

While discussing focus event delivery, Sun tells us:

"Each event includes information about the "opposite" Component or Window
involved in the focus or activation change. For example, for a FOCUS_GAINED event, the opposite Component is the Component that lost
focus. If the focus or activation change occurs with a native application, with
a Java application in a different VM or context, or with no other Component,
then the opposite Component or Window is null. This information is accessible
using FocusEvent.getOppositeComponent or WindowEvent.getOppositeWindow.

On some platforms, it is not possible to discern the opposite Component or
Window when the focus or activation change occurs between two different
heavyweight Components. In these cases, the opposite Component or Window may be
set to null on some platforms, and to a valid non-null value on other platforms.
However, for a focus change between two lightweight Components which share the
same heavyweight Container, the opposite Component will always be set correctly.
Thus, a pure Swing application can ignore this platform restriction when using
the opposite Component of a focus change that occurred within a top-level
Window."

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 figures and listings while you are reading about
them.

Supplementary material

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

Preview

In this lesson, I will show you how to use a feature of the focus
subsystem to find the opposite component when a particular component
gains or loses the focus.

If that particular component gains the focus, the opposite component is the
component that lost the focus.

If that particular component loses the focus, the opposite component is the
component that gained the focus.

Discussion and Sample
Code

Focus traversal

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

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

Traversal typically uses keys

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

Keyboard is not required

However, keyboard action isn’t always required.  It is also possible for
program code to initiate traversal through the execution of program
instructions.

Description of the program

This lesson presents and explains a program named FocusOpposite01.

This program illustrates the ability to programmatically determine
the opposite component on a focusGained or
focusLost event.

The program GUI

The program causes a single JFrame object to appear on the screen as
shown in Figure 1.



Figure 1 Screen display.

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

Two JLabel objects appear in the center of
the frame.  These labels are used to display
focus information regarding the button in the
twelve o’clock position.

Keyboard focus traversal

When the program first starts running, the
button with the caption 12 has the focus, and the default focus policy applies. 
According to the default focus policy, successively
pressing the tab key causes the focus to
traverse the buttons left to right, top to
bottom.  Thus, the forward focus traversal path is as follows:  12, 09, 03, 06, and back to 12.

Holding down the Shift key and successively
pressing the tab key causes the focus to traverse
the buttons in the reverse direction.

Clicking any of the four buttons with the mouse causes it to gain the focus.

When button 12 gains the focus …

Each time the button in the twelve o’clock
position gains the focus for any reason, the
“opposite” component that lost the focus is
identified in one of the labels in the center
of the frame.

The fact that the button in the
twelve o’clock position gained the focus is also
indicated in the center of
the frame.

When button 12 loses the focus …

Each time the button in the twelve o’clock
position loses the focus for any reason, the
“opposite” component that gained the focus is
identified in one of the labels in the center
of the frame.

The fact that the button in the
twelve o’clock position lost the focus is also
indicated in the center of
the frame.

SDK V1.4 or later is required

This program requires SDK V1.4 or later to run correctly.  It was tested using
SDK 1.4.2 under WinXP.

Will discuss in fragments

I will discuss this program in fragments.  A complete listing of the
program is provided in Listing 6 near the end of the lesson.

Listing 1 shows the entire class named FocusOpposite01, including the
main method.

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

Listing 1

The code in Listing 1 instantiates a new object of the GUI class. 
This object produces the screen display shown in Figure 1.

The GUI class

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

class GUI extends JFrame{
  JLabel labelA = new JLabel(
                          "Display output here");
  JLabel labelB = new JLabel("");
  JPanel panel = new JPanel();
  JButton button12 = new JButton("12");
  JButton button03 = new JButton("03");
  JButton button06 = new JButton("06");
  JButton button09 = new JButton("09");
  JFrame frame = this;

Listing 2

The code in Listing 2 instantiates several buttons and other components
required to construct the GUI object shown in Figure 1.

Listing 2 also creates a reference variable of type JFrame named
frame
and initializes it with a reference to the GUI object.

The GUI constructor

The constructor for the GUI class begins in Listing 3.

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

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

    frame.setVisible(true);

Listing 3

The code in Listing 3 places each of the components in the JFrame in
order to construct the GUI object.  Then the code in Listing 3
causes the GUI object to become visible on the screen.

An anonymous focus listener class

Listing 4 shows the beginning of an anonymous inner class that is used to register a
focus listener on the button at twelve o’clock.

(If you are unfamiliar with the use of anonymous inner classes for
listener registration, you will find other tutorial lessons that explain
that concept on my web site.)

    //Register focus listener on the twelve
    //o'clock button
    button12.addFocusListener(
      new FocusListener(){
        public void focusGained(FocusEvent e){
          labelA.setText("");
          labelB.setText("");
          Component lost =
                        e.getOppositeComponent();
          if(lost != null && lost instanceof
                                        JButton){
            labelA.setText("Lost: " +
                           ((JButton)lost).
                             getActionCommand());
          }//end if

          Object gained = e.getSource();
          if(gained != null && gained instanceof
                                        JButton){
            labelB.setText("Gained: " +
                           ((JButton)gained).
                             getActionCommand());
          }//end if
        }//end focusGained

Listing 4

The focusGained event handler method

Listing 4 shows the entire definition for the focusGained event
handler method.

The one thing in Listing 4 that is new to this lesson is the invocation of
the getOppositeComponent method on the incoming FocusEvent object. 
The getOppositeComponent method returns a reference to the component that lost the focus when the
button at twelve o’clock gained the focus.

What does Sun have to say?

Sun has this to say about the getOppositeComponent method:

"Returns the other Component involved in this focus change.

For a FOCUS_GAINED event, this is the Component that lost focus.

For a FOCUS_LOST event, this is the Component that gained focus.

If this focus change occurs with a native application, with a Java
application in a different VM or context, or with no other Component, then
null is returned."

The remaining code in focusGained …

The remaining code in the focusGained method in Listing 4:

  • Gets a reference to the object that gained the focus.
  • Confirms that neither that reference nor the reference to the
    opposite
    component is null.
  • Confirms that both references refer to objects of type JButton
  • Displays the identification of the button that gained the focus and the
    button that lost the focus in the labels in the center of the frame.

The focusLost event handler method

Listing 5 shows the remaining code in the anonymous focus listener class.

        public void focusLost(FocusEvent e){
          labelA.setText("");
          labelB.setText("");
          Object lost = e.getSource();
          if(lost != null && lost instanceof
                                        JButton){
            labelA.setText("Lost: " +
                           ((JButton)lost).
                             getActionCommand());
          }//end if

          Component gained =
                        e.getOppositeComponent();
          if(gained != null && gained instanceof
                                        JButton){
            labelB.setText("Gained: " +
                           ((JButton)gained).
                             getActionCommand());
          }//end if
        }//end focusLost
      }//end new FocusListener
    );//end addFocusListener

  }//end constructor
}//end GUI

Listing 5

Listing 5 contains the entire focusLost event handler method. 

Behavior of the focusLost method

The behavior of the focusLost method is essentially the reverse of the
behavior of the
focusGained
method shown in Listing 4.

Whenever the button at twelve o’clock loses the focus, the code in the
focusLost
method invokes the getOppositeComponent method to identify
the component that gained the focus.

Then both components are displayed in
the labels in the center of the frame.

End of constructor and GUI class

Listing 5 also signals the end of the constructor for the GUI class
and the end of the GUI class.

Run the Program

I encourage you to copy, compile, and run the program provided in this lesson. 
Experiment with it, making changes and observing the results of your changes.

Summary

I showed you how to use a feature of the focus
subsystem to find the opposite component when a particular component gains or
loses the focus.

If that particular component gains the focus, the opposite component is the
component that lost the focus.

If that particular component loses the focus, the opposite component is the
component that gained the focus.

What’s Next?

Future lessons will discuss other focus features including the
following:

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

Complete Program Listing

A complete listing of the program discussed in this lesson is provided below.

/*File FocusOpposite01.java
Copyright 2004 R.G.Baldwin

This program illustrates the ability to determine
the opposite component on a focusGained or
focusLost event.

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

Two blank JLabel objects appear in the center of
the frame.  These labels are used to display
focus information regarding the button in the
twelve o'clock position.

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

The default focus policy applies.  Successively
pressing the tab key causes the focus to
traverse the buttons left to right, top to
bottom:  12, 09, 03, 06, and back to 12.

Holding down the Shift key and successively
pressing the tab key causes the focus to traverse
the buttons in the reverse direction.

Each time the button in the twelve o'clock
position gains the focus for any reason, the
"opposite" component that lost the focus is
identified in one of the labels in the center
of the frame.  The fact that the button in the
twelve o'clock position gained the focus is also
indicated in the other label in the center of
the frame.

Each time the button in the twelve o'clock
position loses the focus for any reason, the
"opposite" component that gained the focus is
identified in one of the labels in the center
of the frame.  The fact that the button in the
twelve o'clock position lost the focus is also
indicated in the other label in the center of
the frame.

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

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

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

class GUI extends JFrame{
  JLabel labelA = new JLabel(
                          "Display output here");
  JLabel labelB = new JLabel("");
  JPanel panel = new JPanel();
  JButton button12 = new JButton("12");
  JButton button03 = new JButton("03");
  JButton button06 = new JButton("06");
  JButton button09 = new JButton("09");
  JFrame frame = this;

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

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

    frame.setVisible(true);

    //Register focus listener on the twelve
    //o'clock button
    button12.addFocusListener(
      new FocusListener(){
        public void focusGained(FocusEvent e){
          labelA.setText("");
          labelB.setText("");
          Component lost =
                        e.getOppositeComponent();
          if(lost != null && lost instanceof
                                        JButton){
            labelA.setText("Lost: " +
                           ((JButton)lost).
                             getActionCommand());
          }//end if

          Object gained = e.getSource();
          if(gained != null && gained instanceof
                                        JButton){
            labelB.setText("Gained: " +
                           ((JButton)gained).
                             getActionCommand());
          }//end if
        }//end focusGained

        public void focusLost(FocusEvent e){
          labelA.setText("");
          labelB.setText("");
          Object lost = e.getSource();
          if(lost != null && lost instanceof
                                        JButton){
            labelA.setText("Lost: " +
                           ((JButton)lost).
                             getActionCommand());
          }//end if

          Component gained =
                        e.getOppositeComponent();
          if(gained != null && gained instanceof
                                        JButton){
            labelB.setText("Gained: " +
                           ((JButton)gained).
                             getActionCommand());
          }//end if
        }//end focusLost
      }//end new FocusListener
    );//end addFocusListener

  }//end constructor
}//end GUI

Listing 6


Copyright 2004, 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.

In addition to his programming expertise, Richard has many years of
practical experience in Digital Signal Processing (DSP).  His first
job after he earned his Bachelor’s degree was doing DSP in the Seismic Research
Department of Texas Instruments.  (TI is still a world leader in DSP.) 
In the following years, he applied his programming and DSP expertise to other
interesting areas including sonar and underwater acoustics.

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