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

JDK 1.1, Lightweight Components, An Anonymous Inner-Class Source/Listener Version of the Lightweight 3D Button Class

Java Programming, Lecture Notes # 182, Revised 02/19/98.

Preface

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

The material in this lesson is extremely important. However, there is simply too much material to be covered in detail during lecture periods. Therefore, students in Prof. Baldwin's Advanced Java Programming classes at ACC will be responsible for studying this material on their own, and bringing any questions regarding the material to class for discussion.

This lesson was originally written on December 6, 1997 using the software and documentation in the JDK 1.1.3 download package.

Introduction

Previous lessons developed and discussed a lightweight 3D button class that mimics a heavyweight button in many respects. One of those lessons developed the lightweight 3D button class using the Source/Listener methodology with named inner classes. The name of the class that was developed in that lesson was LWButton02.

This lesson will develop a new class for the lightweight button by converting two of the named inner classes to anonymous inner classes.

All of the class definition will remain the same except for the constructor and the removal of the two named inner classes. Therefore, all I am only going to show you is the constructor.

You can create your own version of this new class by using the new constructor, removing the named inner classes for the focus listener and the key listener from the class named LWButton02, and using the remainder of the class named LWButton02.

I'm not going to provide much discussion. You should already know how to convert the named inner classes to anonymous inner classes. If you don't, you should go back and review the lesson on inner classes.

A test program is provided at the end of the lesson that can be used to exercise this new version of the lightweight button class.

Please refer to the class named LWButton01 in a previous lesson for a complete functional description of the lightweight 3D button class.

Interesting Code Fragments

The only interesting code fragments are the two anonymous inner class definitions which are shown below. The first is the inner class definition used to register a key listener object and the second is the inner class definition used to register a focus listener object.

Note that when you define an anonymous inner class, you are, in effect, implementing the listener interface. This requires that you provide a definition for all of the methods declared in the interface. Therefore, it was necessary for me to provide an empty function definition for the method named keytyped() even though I didn't need to use that method.

Also note that it wasn't possible to use an anonymous inner class for the mouse listener. Use of an anonymous inner class implies that you are instantiating an anonymous object. However, the functional requirements of the program require that the methods of the key listener object invoke methods of the mouse listener object. This requires that the mouse listener object be a named object. You can see that in the following code which references the mousePressed() and mouseReleased() methods on the mouseListener object.
 
    //Register an anonymous key listener object using an 
    // anonymous inner class
    this.addKeyListener(
      new KeyListener(){
        public void keyPressed(KeyEvent e){
        //Generate mousePressed() event
        if(e.getKeyCode() == KeyEvent.VK_SPACE) 
        mouseListener.mousePressed(new MouseEvent(
                        refToThis,MouseEvent.MOUSE_PRESSED,
                                         0,0,0,0,0,false));
        }//end keyPressed()
        
        public void keyReleased(KeyEvent e){
        //Generate mouseReleased() event 
        if(e.getKeyCode() == KeyEvent.VK_SPACE)
        mouseListener.mouseReleased(new MouseEvent(
                       refToThis,MouseEvent.MOUSE_RELEASED,
                                         0,0,0,0,0,false));
        }//end keyReleased()
          
        public void keyTyped(KeyEvent e){}//satisfy compiler
      }//end KeyListener
    );//end addKeyListener
    //end of anonymous inner class for key listener
    
The next code fragment shows the registration of the anonymous focus listener object using an anonymous inner class.
 
    //Register an anonymous focus listener object using an
    // anonymous inner class.
    this.addFocusListener(
      new FocusListener(){
        public void focusGained(FocusEvent e){
          gotFocus = true; //set the gotFocus flag  
          refToThis.invalidate();      
          refToThis.repaint();
        }//end focusGained()  
        
        public void focusLost(FocusEvent e){
          gotFocus = false; //clear the gotFocus flag    
          refToThis.invalidate();      
          refToThis.repaint();
        }//end focusLost()        
      }//end FocusListener
    );//end addFocusListener
    //end of anonymous inner class for focus listener    
A complete listing of the constructor as well as some of the comments from the beginning of the program are provided in the next section.

It was pointed out by a reader named Kees Kuip that the use of the refToThis instance variable could lead to a memory leak, because the object has an embedded reference to itself which could prevent it from being garbage-collected. A solution to this potential problem was provided as an exercise for the student in the Review section at the end of an earlier lesson. As it turns out, this is not a problem. A demonstration program to that effect was also provided in the earlier lesson. Thanks go out to Kees for pointing out this potential problem, and also for recommending a solution.

Constructor Listing for New Lightweight Button Class

This constructor listing is followed by a listing for a program that can be used to exercise the new version of the lightweight button.
 
/* File LWButton03.java Copyright 1997, R.G.Baldwin
This class replicates the functionality of the class
named LWButton01 and is a modification of the class named
LWButton02.

However, the LWButton01 class was implemented using the 
enableEvents()--process...Event() methodology whereas this
class uses the source/listener methodology.  

Two of the listener classes in this class are anonymous
inner classes while one of the listener classes is a named
inner class.  

This class was tested using JDK 1.1.3 under Win95.
*/
//=======================================================//

  //Constructor for an LWButton with a label.
  public LWButton03(String rawLabel) {
    this.rawLabel = rawLabel;
    //Add spaces on either end and save it that way
    this.label = "  " + rawLabel + "  ";

    //Instantiate and register a named listener object for
    // the mouse listener.
    mouseListener = new MyMouseListenerClass();
    this.addMouseListener(mouseListener);

    //Register an anonymous key listener object using an 
    // anonymous inner class
    this.addKeyListener(
      new KeyListener(){
        public void keyPressed(KeyEvent e){
        //Generate mousePressed() event
        if(e.getKeyCode() == KeyEvent.VK_SPACE) 
        mouseListener.mousePressed(new MouseEvent(
                        refToThis,MouseEvent.MOUSE_PRESSED,
                                         0,0,0,0,0,false));
        }//end keyPressed()
        
        public void keyReleased(KeyEvent e){
        //Generate mouseReleased() event 
        if(e.getKeyCode() == KeyEvent.VK_SPACE)
        mouseListener.mouseReleased(new MouseEvent(
                       refToThis,MouseEvent.MOUSE_RELEASED,
                                         0,0,0,0,0,false));
        }//end keyReleased()
          
        public void keyTyped(KeyEvent e){}//satisfy compiler
      }//end KeyListener
    );//end addKeyListener
    //end of anonymous inner class for key listener
    
    //Register an anonymous focus listener object using an
    // anonymous inner class.
    this.addFocusListener(
      new FocusListener(){
        public void focusGained(FocusEvent e){
          gotFocus = true; //set the gotFocus flag  
          refToThis.invalidate();      
          refToThis.repaint();
        }//end focusGained()  
        
        public void focusLost(FocusEvent e){
          gotFocus = false; //clear the gotFocus flag    
          refToThis.invalidate();      
          refToThis.repaint();
        }//end focusLost()        
      }//end FocusListener
    );//end addFocusListener
    //end of anonymous inner class for focus listener    
   
    
    //Store a reference to this lightweight button object 
    // in an instance variable 
    refToThis = this;                 
  }//end constructor
The next section contains the source code for a program that can be used to exercise this lightweight button class.

Test Program Listing

The following test program is identical to one of the test programs in a previous program that was used to exercise the earlier version of the lightweight button class with a BorderLayout manager. Only the reference to the lightweight button class has been changed.

Please refer to the earlier lesson for a functional description of the program.
 
/* File Lightweight08.java Copyright 1997, R.G.Baldwin

This program was tested using JDK 1.1.3 under Win95.
*/
//=======================================================//
import java.awt.*;
import java.awt.event.*;
//=======================================================//
public class Lightweight08 extends Frame{
  Label myLabel;
  
  public static void main(String[] args){
    new Lightweight08();//instantiate object of this type
  }//end main

//-------------------------------------------------------//
  public Lightweight08(){//constructor
    this.setTitle("Copyright 1997, R.G.Baldwin");
    //Set background to a dull yellow
    this.setBackground(new Color(128,128,0));
    
    //Create a borderLayout object with gaps and apply
    // it to the Frame object.
    BorderLayout myLayout = new BorderLayout();
    myLayout.setHgap(10);
    myLayout.setVgap(10);
    this.setLayout(myLayout);    
    
    //Instantiate three lightweight buttons
    LWButton03 eastLWButton = new LWButton03("East");
    LWButton03 northLWButton = new LWButton03("North");
    LWButton03 centerLWButton = new LWButton03("Center");
    
    //Instantiate a Label object and initialize it to green
    myLabel = new Label("Label Object");
    myLabel.setBackground(Color.green);
    
    //Instantiate a heavyweight button object
    Button myButton = new Button("Heavyweight Button");
    
    //Add all five components to the Frame object.
    this.add(eastLWButton,"East");    
    this.add(northLWButton,"North");    
    this.add(centerLWButton,"Center");
    this.add(myButton,"West");
    this.add(myLabel,"South");

    //Instantiate an ActionListener object
    MyActionListener myActionListener = 
                                   new MyActionListener();
                             
    //Register the ActionListener object on all four
    // of the buttons.                             
    eastLWButton.addActionListener(myActionListener);
    northLWButton.addActionListener(myActionListener);
    centerLWButton.addActionListener(myActionListener);
    myButton.addActionListener(myActionListener);
    
    this.setSize(300,200);
    this.setVisible(true);

    //Anonymous inner-class listener to terminate program
    this.addWindowListener(new WindowAdapter(){
               public void windowClosing(WindowEvent e){
                 System.exit(0);}});//end addWindowListener
  }//end constructor
  //-----------------------------------------------------//
  
  //Inner Class to respond to action events.  Make this an
  // inner class for easy access to myLabel.
  class MyActionListener implements ActionListener{
    public void actionPerformed(ActionEvent e){
      if(myLabel.getBackground() == Color.green)
        myLabel.setBackground(Color.red);
      else myLabel.setBackground(Color.green);
    }//end actionPerformed
  }//end class MyActionListener
}//end class Lightweight08
//=======================================================//
-end-