Richard G Baldwin (512) 223-4758, baldwin@austin.cc.tx.us, http://www2.austin.cc.tx.us/baldwin/

Event Handling in JDK 1.1, Requesting the Focus

Java Programming, Lecture Notes # 86, Revised 03/09/98.

Preface

Students in Prof. Baldwin's Intermediate Java Programming classes at ACC are responsible for knowing and understanding all of the material in this lesson.

Introduction

An earlier lesson briefly discussed the focusGained() and focusLost() events in the Delegation Event Model of JDK 1.1.

This lesson takes another look at that topic through the use of a program which forces an object which doesn't usually gain the focus in typical Windows programs (a Label object) to

This lesson is intended to illustrate the power, consistency, and flexibility of the new Delegation Event Model in JDK 1.1.

Overview

A major weakness of the Inheritance Event Model in JDK 1.0.2 has to do with decisions made by the runtime system as to the type of events it will generate for visual components.

For example, in JDK 1.0.2, it is apparently not possible for a TextField object to generate a mouse event because the runtime system which creates Event objects and passes them to the postEvent() method simply doesn't create mouse events for TextFields.

Many, and possibly all, of these restrictions have been removed in the Delegation Event Model of JDK 1.1. The Delegation Event Model provides for a wide array of event types across a wide array of visual component types.

It appears that in JDK 1.1, most of the standard visual components can generate any of the low-level events that make any sense (although I haven't tested all combinations of components and events).

In this lesson, we use a combination of low-level focus, mouse, and keyboard events to cause a Frame, a Label, a Button, and a TextField all to

(Note that prior to 9/5/97, this section erroneously referred to focus events as semantic events.)

Note that Windows programs and RAD environments in BASIC, C++, and Pascal often do not provide keyboard event support for Labels and Frames and often do not allow Labels to gain the focus.

Having a Label gain the focus and respond to keyboard events may not be particularly useful by conventional standards, but the ability to cause it to do so illustrates the power of the Delegation Event Model in JDK 1.1.

The Sample Program

This section will present a discussion of the program followed by the program listing.

Discussion

This program is fairly long, but it is also fairly repetitive.

The fact that it is repetitive speaks well for the Delegation Event Mode.

The code syntax required to handle one type of event on one type of object is very similar to the code required to handle other types of events on the same or different objects.

Once you learn the syntax, you should be able to write programs that are generally error free.

A Button object, a TextField object, and a Label object are placed in a Frame object.

Normally you cannot see the outline of a Label object, so its background color is made yellowso that it will show up in the white expanse of the Frame object.

Focus Event Processing

A FocusListener object is instantiated and registered to listen for focusGained() and focusLost() events on the Frame and the Label. When these events occur, the FocusListener object makes a color change on the Frame or the Label to provide a visual indication of focus gained or lost.

One of the benefits of the Delegation Event Model is the ability to filter events so that event-handler code needs to deal only with those events that are of interest.

In this particular program, the TextField object and the Button object also generate focus events. However, there was no reason to process them, so the FocusListener object simply wasn't registered to be notified when they occurred.

In JDK 1.0.2, the filtering of events to only those handlers that needed to deal with them isn't nearly as clean.

When the Label has the focus, its text is red. Otherwise, its text is black.

When the Frame has the focus, its background color is blue. Otherwise, it is white.

Note that the Button and the TextField components automatically provide a visual indication of focus without intervention by the programmer.

Mouse Event Processing

A MouseListener object is instantiated and registered to listen for low-level mousePressed() events on the Frame and the Label. (The above comments regarding event filtering apply here also.)

When such an event occurs, the MouseListener object invokes requestFocus() on the visual component object. This causes the Label and the Frame to receive the focus when clicked on. This is decidedly unusual behavior for a Label object.

Note that the Button and the TextField automatically receive the focus when clicked on without intervention by the programmer.

Keyboard Event Processing

A KeyListener object is instantiated and registered to listen for keyPressed() events on the Frame, Label, Button, and TextField objects.

Whenever a key is pressed, the object currently holding the focus generates a keyPressed() event, even if it is a type of object that we don't normally expect to respond to the keyboard (such as the Label).

The KeyListener object determines which visual component generated the event and displays a message to that effect.

Thus, the Label and the Frame which don't normally respond to the keyboard are forced to respond to the keyboard in this program.

The comments at the beginning of the program show the messages generated by each of the four visual components when a key is pressed while that component has the focus.

Window Event Processing

Finally, a WindowListener object is instantiated and registered to terminate the program when the user closes the Frame object. We have used this type of event processing in previous lessons so there is nothing new here.

Automatic Component Naming

Whenever an object of the Component class is instantiated, it is automatically given a component name.

That name can be accessed using the getName() method of the Component class, and it can be changed using the setName() method of the Component class.

This program uses the component name to determine which component generated an event in those cases where there is a choice.

A sample program in a previous lesson established the names of various components using the setName() method of the Component class. However, it was pointed out at that time that the Beta 3 version of JDK 1.1 does not enforce a requirement for unique component names when those names are set by code in the program. This can lead to problems if the programmer isn't careful to always assign unique names.

This program assumes that the names which are automatically given to the components are unique and instead of assigning names for later use in distinguishing among components, it retrieves and saves the names which are automatically assigned. These names are later used to distinguish among components to determine which component generated an event.

Program Listing

A listing of the program follows. Additional information about the operation of the program is provided in the comments.
 
/*File Event15.java Copyright 1997, R.G.Baldwin
Revised 03/09/98 to fit on the page better.

This program is designed to be compiled and run 
under JDK 1.1

Illustrates how visual components such as Label objects can
be forced to gain the focus, and can then respond to 
keyboard events while they have the focus.  (Note that, by
convention, Label objects don't typically gain the focus 
and don't usually respond to the keyboard in typical 
Windows programs.)

A Button object, a TextField object, and a Label object are
placed in a Frame object.

A FocusListener object is instantiated and registered to 
listen for focusGained() and focusLost() events on the 
Frame and the Label.  When these events occur, the listener
object makes a color change on the Frame or Label to 
provide a visual indication of focus gained or lost.  

When the Label has the focus, its text is red.  Otherwise,
its text is black.  When the Frame has the focus, its 
background color is blue. Otherwise, it is white.

Note that the Button and the TextField components 
automatically provide a visual indication of focus without
intervention by the programmer.

A MouseListener object is instantiated and registered to 
listen for low-level mousePressed() events on the Frame and
the Label.  When such an event occurs, the mouse listener 
object invokes requestFocus() on the object that was the 
source of the mouse event. This causes the Label and the 
Frame to receive the focus when clicked on.

Note that the Button and the TextField automatically 
receive the focus when clicked on without intervention by 
the programmer.

A KeyListener object is instantiated and registered to 
listen for keyPressed() events on the Frame, Label, Button,
and TextField objects.  

Whenever a key is pressed, the object currently holding the
focus generates a keyPressed() event.  The KeyListener 
object determines which component generated the event and 
displays a message to that effect.  Thus, the Label and the
Frame which "don't normally respond" to the keyboard are 
forced to respond to the keyboard in this program.

Finally, a WindowListener object is instantiated and 
registered to terminate the program when the user closes 
the Frame object.


Pressing a key causes messages such as the following to be
displayed:

Got keyPressed event from textfield0
Got keyPressed event from frame0
Got keyPressed event from label0
Got keyPressed event from button0

This program retrieves and saves the component names 
automatically assigned to the visual components (under the
assumption that the system will assign unique names) and 
uses those names to determine which component generated an
event when such determination is necessary.

These results were produced using JDK 1.1.3 under Win95
**********************************************************/

import java.awt.*;
import java.awt.event.*;

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

//The following class is used to instantiate a graphical 
// user interface object.
class GUI {
  //save automatic component name here
  String myTextFieldName; 
  String myButtonName;
  String myFrameName;
  String myLabelName;
  Frame myFrame;//ref variable passed as parameter
  Label myLabel;

  public GUI(){//constructor
    //Create several visual components 
    TextField myTextField = new TextField(
                                       "TextField Object");
    //save the name of the component
    myTextFieldName = myTextField.getName();

    myLabel = new Label("LabelObject");
    myLabelName = myLabel.getName();
    //make it yellow so it will show up
    myLabel.setBackground(Color.yellow);

    Button myButton = new Button("Button Object");
    myButtonName = myButton.getName();
  
    myFrame = new Frame();
    myFrame.setSize(250,300);
    myFrame.setTitle("Copyright 1997, R.G.Baldwin");
    myFrameName = myFrame.getName();
    
    //Add the other objects to the frame using default 
    // border layout manager
    myFrame.add("North",myButton);
    myFrame.add("South",myTextField);
    myFrame.add("West",myLabel);
    
    myFrame.setVisible(true);//make the frame visible
    //shift the focus to the TextField
    myTextField.requestFocus();

    //Instantiate and register a FocusListener object which
    // will process focus events on two different visual 
    // components.  In this case, the listener object makes
    // a color change on the visual component to indicate 
    // focus gained or focus lost.
    myFocusListener focusHandler = 
                                 new myFocusListener(this);
    myFrame.addFocusListener(focusHandler);  
    myLabel.addFocusListener(focusHandler);
    
    //Instantiate and register a MouseListener object which
    // will process mouse events on two different visual 
    // components.  In this case, the listener object 
    // specifically requests focus for the Label and the 
    // Frame components when those components are clicked 
    // on.
    
    myMouseListener mouseHandler = 
                                 new myMouseListener(this);
    myFrame.addMouseListener(mouseHandler);
    myLabel.addMouseListener(mouseHandler);    
    
    //Instantiate and register a KeyListener object which
    // will process key events on four different
    // components.  Whenever a key is pressed, a message is
    // displayed showing that the component that had the 
    // focus received a keyPressed event.
    myKeyListener keyHandler = new myKeyListener(this);
    myFrame.addKeyListener(keyHandler);
    myTextField.addKeyListener(keyHandler);
    myButton.addKeyListener(keyHandler);
    myLabel.addKeyListener(keyHandler);    
    

    //Instantiate and register a WindowListener object 
    // which will terminate the program when the user 
    // closes the Frame object
    WProc1 winProcCmd1 = new WProc1();
    myFrame.addWindowListener(winProcCmd1);
  }//end constructor
}//end class GUI definition
//=======================================================//

//This FocusListener class is used to instantiate a 
// Listener object that listens for focus events on the 
// Frame and the Label. Whenever a focusLost() or 
// focusGained() event occurs, it makes a color change on 
// the component to provide a visual indication of the
// gain or loss of focus.

class myFocusListener implements FocusListener{
  GUI thisObject;
  
  myFocusListener(GUI thisObjectIn){//constructor
    thisObject = thisObjectIn;
  }// end constructor
  
  public void focusGained(FocusEvent e){
    if( e.toString().indexOf("on " + 
                           thisObject.myFrameName) != -1 ){
      thisObject.myFrame.setBackground(Color.blue);
    }//end if
    if( e.toString().indexOf("on " + 
                           thisObject.myLabelName) != -1 ){
      thisObject.myLabel.setForeground(Color.red);
    }//end if
    thisObject.myFrame.repaint();
  }//end focusGained()

  public void focusLost(FocusEvent e){
    if( e.toString().indexOf("on " + 
                           thisObject.myFrameName) != -1 ){
      thisObject.myFrame.setBackground(Color.white);      
    }//end if       
    if( e.toString().indexOf("on " + 
                           thisObject.myLabelName) != -1 ){
      thisObject.myLabel.setForeground(Color.black);      
    }//end if       
    thisObject.myFrame.repaint();
  }//end focusLost()
}//end class myFocusListener
//=======================================================//

//This listener class listens for mouse presses on the 
// Frame and Label components.  These components do not
// automatically receive the focus when clicked with the
// mouse.  This listener class requests the focus for these
// components when they are clicked on with the mouse.

class myMouseListener extends MouseAdapter{
  GUI thisObject;
  
  myMouseListener(GUI thisObjectIn){//constructor
    thisObject = thisObjectIn;
  }//end constructor
  public void mousePressed(MouseEvent e){
    if( e.toString().indexOf("on " + 
                           thisObject.myFrameName) != -1 ){
      thisObject.myFrame.requestFocus();
    }//end if

    if( e.toString().indexOf("on " + 
                           thisObject.myLabelName) != -1 ){
      thisObject.myLabel.requestFocus();
    }//end if
    
  }//end mousePressed()
}//end class myMouseListener
//=======================================================//

//This listener class listens for key presses and displays
// a message when a keyPressed() event occurs. The
// component that has the focus when the keyPress event
// occurs generates the event.  This class identifies the
// component that generated the event and displays a 
// message identifying that component.

// The significant thing here is that any component that
// has the focus will generate a keyPress event, including
// those components, such as Label objects, which don't
// "normally" have the focus.

class myKeyListener extends KeyAdapter{
  GUI thisObject;
  
  myKeyListener(GUI thisObjectIn){//constructor
    thisObject = thisObjectIn;
  }//end constructor

  public void keyPressed(KeyEvent e){
    if( e.toString().indexOf("on " + 
                           thisObject.myFrameName) != -1 ){
      System.out.println("Got keyPressed event from " +
                                   thisObject.myFrameName);
    }//end if

    if( e.toString().indexOf("on " + 
                       thisObject.myTextFieldName) != -1 ){
      System.out.println("Got keyPressed event from " +
                               thisObject.myTextFieldName);
    }//end if

    if( e.toString().indexOf("on " + 
                          thisObject.myButtonName) != -1 ){
      System.out.println("Got keyPressed event from " +
                                  thisObject.myButtonName);
    }//end if

    if( e.toString().indexOf(
                   "on " + thisObject.myLabelName) != -1 ){
      System.out.println("Got keyPressed event from " +
                                   thisObject.myLabelName);
    }//end if
    
  }//end keyPressed()
}//end class myKeyListener
//=======================================================//

//The following listener is used to terminate the 
// program when the user closes the Frame object.
class WProc1 extends WindowAdapter{
  public void windowClosing(WindowEvent e){
    System.exit(0);
  }//end windowClosing()
}//end class WProc1
//=======================================================//
This program contains a lot of useful information about event handling in general and focus in particular in JDK 1.1. It would be well for you to study it and understand how it works.

Review

Q - Without viewing the following solution, write a Java application that illustrates the use of the focusGained and focusLost events along with the keyPressed event.

A Button object and a TextField object are placed in a Frame object. Focus can be moved between the two by pressing the tab key or clicking on them with the mouse.

A WindowListener object is instantiated and registered to terminate the program when the user closes the Frame object. Pressing the tab key causes messages such as the following to be displayed:

Got keyPressed event from button0
java.awt.event.FocusEvent[FOCUS_LOST,permanent] on button0
java.awt.event.FocusEvent[FOCUS_GAINED,permanent] on textfield0
Got keyPressed event from textfield0
java.awt.event.FocusEvent[FOCUS_LOST,permanent] on textfield0
java.awt.event.FocusEvent[FOCUS_GAINED,permanent] on button0
A - See program below.
 
/*File SampProg124.java from lesson 86
Copyright 1997, R.G.Baldwin
*/
//=========================================================

import java.awt.*;
import java.awt.event.*;

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

class GUI {
  String myTextFieldName; //save component names here
  String myButtonName;
  
  public GUI(){//constructor
    //Create visual components 
    TextField myTextField = 
      new TextField("TextField Object");
    myTextFieldName = myTextField.getName();//save the name

    Button myButton = new Button("Button Object");
    myButtonName = myButton.getName();//save the name
  
    Frame myFrame = new Frame();
    myFrame.setSize(250,100);
    myFrame.setTitle("Copyright 1997, R.G.Baldwin");
    
    //Add objects to the frame using default border 
    // layout manager
    myFrame.add("North",myButton);
    myFrame.add("South",myTextField);
    
    myFrame.setVisible(true);//make the frame visible
 
    //Instantiate and register a FocusListener object
    myFocusListener focusHandler = new myFocusListener();
    myButton.addFocusListener(focusHandler);
    myTextField.addFocusListener(focusHandler);
    
    //Instantiate and register a KeyListener object 
    myKeyListener keyHandler = new myKeyListener(this);
    myTextField.addKeyListener(keyHandler);
    myButton.addKeyListener(keyHandler);

    //Instantiate and register a WindowListener object 
    // which will terminate the program when the user 
    // closes the Frame object
    WProc1 winProcCmd1 = new WProc1();
    myFrame.addWindowListener(winProcCmd1);
  }//end constructor
}//end class GUI definition
//=========================================================

//This FocusListener class is used to instantiate a 
// Listener object that listens for focus events on the 
// button and textField components. Whenever a focusLost() 
// or focusGained() event occurs, it displays a message to 
// that effect.

class myFocusListener implements FocusListener{
  
  public void focusGained(FocusEvent e){
    System.out.println(e.toString());
  }//end focusGained()

  public void focusLost(FocusEvent e){
    System.out.println(e.toString());    
  }//end focusLost()
}//end class myFocusListener
//=========================================================

//This listener class listens for key presses and displays
// a message when a keyPressed() event occurs. The visual 
// component that has the focus when the keyPress event 
// occurs generates the event.  This class identifies the 
// component that generated the event and displays a 
// message identifying that component.

class myKeyListener extends KeyAdapter{
  GUI thisObject;
  
  myKeyListener(GUI thisObjectIn){//constructor
    thisObject = thisObjectIn;
  }//end constructor

  public void keyPressed(KeyEvent e){
    if( e.toString().indexOf("on " 
                     + thisObject.myTextFieldName) != -1 ){
      System.out.println("Got keyPressed event from " 
                             + thisObject.myTextFieldName);
    }//end if

    if( e.toString().indexOf("on " 
                        + thisObject.myButtonName) != -1 ){
      System.out.println("Got keyPressed event from " 
                                + thisObject.myButtonName);
    }//end if
  }//end keyPressed()
}//end class myKeyListener
//=========================================================

//The following listener is used to terminate the 
// program when the user closes the Frame object.
class WProc1 extends WindowAdapter{
  public void windowClosing(WindowEvent e){
    System.exit(0);
  }//end windowClosing()
}//end class WProc1
//=========================================================
-end-