Java Programming, Lecture Notes # 252, Revised 12/17/98.
Students in Prof. Baldwin's Advanced Java Programming classes at ACC are responsible for knowing and understanding all of the material in this lesson.
This lesson was originally written on February 28, 1997 using the software and documentation in JDK 1.1. It was upgraded to JDK 1.2 on December 16, 1998.
One of the features of JDK 1.1 is the ability to create persistent objects using object serialization.
Another feature is the Delegation Event Model which, among other things, uses a source/listener model for handling events.
A third feature is the ability to create inner classes and also to use an abbreviated syntax for the definition of anonymous classes and the instantiation of anonymous objects from those classes.
The definition of anonymous classes and the instantiation of anonymous objects of those classes forms a good match for the need to define Listener classes and instantiate Listener objects in the Delegation Event Model.
The purpose of this lesson is to illustrate the use of the Delegation Event Model along with the use of inner classes and object serialization to achieve persistence of a GUI context.
This program uses object serialization to create a persistent GUI object which includes the use of inner classes and the abbreviated syntax for defining new Listener classes and instantiating objects of those classes. The GUI context makes use of the Source/Listener model for event handling that became available with JDK 1.1.
This application combines
to create, save, and later restore an operational GUI object.
The application creates a serializable GUI object having two buttons and a close box. It uses object serialization to write the object to an output file. It closes the file and flushes the output buffer. Then it disposes of the original object.
Then it reopens the file, uses object serialization to read the object from the file and reconstruct it. It assigns the reconstructed object to a new reference variable. The reconstructed object contains a method named activate(), which, when invoked, causes it to become active.
The instance method named activate() is invoked on the reconstructed object to instantiate listener objects and register them to listen for actionPerformed() events on the two buttons and to listen for windowClosing() events on the Frame.
This activation causes the object which was read from the disk file to become operational as a user interface.
The code used to handle the events is based on the source/listener concept of the Delegation Event Model. The code also makes heavy use of inner classes and the abbreviated instantiation syntax.
The first fragment shows the import directives and the definition of the controlling class for the program. The main() method in the controlling class does nothing more than to kick off the process.
import java.io.*; import java.util.*; import java.awt.*; import java.awt.event.*; //=======================================================// class ObjSer02{ static public void main(String[] args){ MyProcess myProcess = new MyProcess(); }//end main() }//end class ObjSer02 |
The next fragment begins the discussion of the class named MyProcess that controls the overall process of creating the GUI, writing it to the disk, reading it back from the disk, and activating it.
The constructor for this class instantiates a new object of type GUI and writes it to the disk in the manner described in an earlier introductory lesson on object serialization. Then it disposes of the GUI object completely, flushes the output stream, and closes the output stream.
class MyProcess{ MyProcess(){//constructor try{ FileOutputStream fout = new FileOutputStream("tmp"); ObjectOutputStream outStream = new ObjectOutputStream(fout); GUI myOldObject = new GUI(); //write a custom GUI object to disk outStream.writeObject(myOldObject); myOldObject.dispose(); outStream.flush(); outStream.close(); |
The next fragment reads the GUI object from the disk in the manner described in an earlier lesson on object serialization. The readObject() method reconstructs the GUI object from the stream of bytes obtained from the disk. A reference to the reconstructed object is assigned to a new reference variable named myNewObject.
Then the activate() method of the reconstructed object is invoked which causes it to become active. We will see later that this method instantiates listener objects and registers them on various components on the GUI object. It also sets the size of the GUI object and makes it visible.
This is followed by typical exception handling catch blocks, ending the definition of the constructor and the definition of the MyProcess class.
FileInputStream fin = new FileInputStream("tmp"); ObjectInputStream inStream = new ObjectInputStream(fin); try{ //read the custom GUI object from the file GUI myNewObject = (GUI)inStream.readObject(); //Invoke one of the objects methods to instantiate // and register listener objects on the components // in the custom GUI. This will make it active. myNewObject.activate(); }catch(ClassNotFoundException e){ System.out.println(e); }//end catch block inStream.close(); }catch(IOException e){System.out.println(e);} }//end constructor }//end class MyProcess |
The next fragment begins the definition of the class from which the GUI object is instantiated.
There is nothing really special about the constructor for this class. You have seen code like this many times in the past. Note however that the constructor does not register listener objects on the components on the GUI. That task is reserved for the method named activate() that we will discuss later.
However, the constructor does make the GUI visible so that you will see it on your screen before it is serialized to disk and disposed. You will see it reappear on the screen when it is read from the disk, reconstructed, and activated by the code in the MyProcess class descussed above.
class GUI extends Frame implements Serializable{ Button singButton; Button whistleButton; public GUI(){//constructor setLayout(new FlowLayout()); setTitle("Copyright 1997, R.G.Baldwin"); setBackground(Color.green); add(singButton = new Button("Sing")); add(whistleButton = new Button("Whistle")); this.setSize(300,75); this.setVisible(true);//display temporarily }//end constructor |
The next fragment is the entire activate() method. This is the method by which the object knows how to make itself active after it is read from the disk and reconstructed.
Recall that this method is invoked on the reconstructed object by the constructor of the MyProcess class.
There is nothing special about this code. It is typical of code used to anonymously instantiate anonymous listener objects and register those listener objects on components.
Two action listeners and one window listener are instantiated and registered by this method when it is invoked. The event handlers in these objects control the behavior of the GUI object after it has been reconstructed.
void activate(){ this.singButton.addActionListener( new ActionListener(){ public void actionPerformed(ActionEvent e){ System.out.println( "I am singing, Tra la la"); }//end actionPerformed() }//end ActionListener );//end addActionListener() this.whistleButton.addActionListener( new ActionListener(){ public void actionPerformed(ActionEvent e){ System.out.println( "I am whistling, Tweet Tweet Tweet"); }//end actionPerformed() }//end ActionListener );//end addActionListener() this.addWindowListener( new WindowAdapter(){ public void windowClosing(WindowEvent e){ System.exit(0);//terminate the program }//end windowClosing() }//end WindowAdapter );//end addWindowListener this.setSize(300,75); this.setVisible(true); this.repaint(); }//end activate() }//end class GUI |
When the user clicks on the button labeled Sing, the event handler registered to listen for Action events on that button displays the following text on the screen.
"I am singing, Tra la la"
When the user clicks on the button labeled Whistle, the event handler registered to listen for Action events on that button displays the following text on the screen.
"I am whistling, Tweet, Tweet, Tweet"
When the user clicks the "close" box on the Frame, the event handler registered to listen for windowClosing() events on the Frame terminates the program.
This program was tested using JDK 1.1 under Win95. It was also tested using JDK 1.2 under Win95.
A listing of the program with additional comments follows:
/*File ObjSer02.java, Copyright 1997, R.G.Baldwin Rev 12/16/98 Designed to be compiled and run under JDK 1.1 or a later version. This application combines object serialization, inner classes, and the Delegation Event Model to create, save in a file, and later restore an operational GUI context. This application creates a serializable GUI object having two buttons and a close box. It uses object serialization to write the object to an output file. It closes the file and flushes. Then it disposes of the original object. Then it reopens the file, uses object serialization to read the object from the file and assigns it to a new reference variable. An instance method named activate() is invoked on the new object to instantiate listener objects and register them to listen for actionPerformed() events on the two buttons and to listen for windowClosing() events on the Frame. The method also sets the size of the Frame containing the GUI, makes it visible, and requests a repaint. This causes the object which was read from the disk file to become operational as a user interface. The code used to handle the events is based on the source/listener concept of the Delegation Event Model. The code also makes heavy use of Inner Classes and the abbreviated instantiation syntax. An instance method named activate() is defined in the GUI class. This method is used to anonymously define the classes for and instantiate three anonymous listener objects. The first two implement the ActionListener interface while the third extends the WindowListener adapter. The first two override the actionPerformed() method of the ActionListener interface while the third overrides the windowClosing() method of the WindowListener interface. The class named GUI extends Frame. Two Button objects labeled Sing and Whistle are instantiated in the GUI constructor. They are referenced by variables named singButton and whistleButton respectively. Both buttons are added to the Frame object. The first two anonymous listener objects mentioned above are registered to listen for actionPerformed() events on the two buttons. The third anonymous listener object is registered to listen for windowClosing() events on the Frame object. When the program starts, a Frame object containing the two buttons appears on the screen momentarily, is written into the file using object serialization, is disposed of and disappears. The file is closed and reopened and the object is read from the file, appears on the screen, and is activated. When the user clicks on the button labeled Sing, the event handler registered to listen for Action events on that button displays the following text on the screen. "I am singing, Tra la la" When the user clicks on the button labeled Whistle, the event handler registered to listen for Action events on that button displays the following text on the screen. "I am whistling, Tweet, Tweet, Tweet" When the user clicks the "close" box on the Frame, the event handler registered to listen for windowClosing() events on the Frame terminates the program. As mentioned above, this version of the program uses abbreviated notation in defining and instantiating the listener objects. The abbreviated notation is fairly cryptic. This program was tested using JDK 1.1 under Win95. It was also tested using JDK 1.2 under Win95. **********************************************************/ import java.io.*; import java.util.*; import java.awt.*; import java.awt.event.*; //=======================================================// class ObjSer02{ static public void main(String[] args){ MyProcess myProcess = new MyProcess(); }//end main() }//end class ObjSer02 //=======================================================// class MyProcess{ MyProcess(){//constructor try{ FileOutputStream fout = new FileOutputStream("tmp"); ObjectOutputStream outStream = new ObjectOutputStream(fout); GUI myOldObject = new GUI(); //write a custom GUI object to disk outStream.writeObject(myOldObject); myOldObject.dispose(); outStream.flush(); outStream.close(); FileInputStream fin = new FileInputStream("tmp"); ObjectInputStream inStream = new ObjectInputStream(fin); try{ //read the custom GUI object from the file GUI myNewObject = (GUI)inStream.readObject(); //Invoke one of the objects methods to instantiate // and register listener objects on the components // in the custom GUI. This will make it active. myNewObject.activate(); }catch(ClassNotFoundException e){ System.out.println(e); }//end catch block inStream.close(); }catch(IOException e){System.out.println(e);} }//end constructor }//end class MyProcess //=======================================================// class GUI extends Frame implements Serializable{ Button singButton; Button whistleButton; public GUI(){//constructor setLayout(new FlowLayout()); setTitle("Copyright 1997, R.G.Baldwin"); setBackground(Color.green); add(singButton = new Button("Sing")); add(whistleButton = new Button("Whistle")); this.setSize(300,75); this.setVisible(true);//display temporarily }//end constructor //-----------------------------------------------------// void activate(){ //The code which follows instantiates three anonymous // objects of types ActionListener and WindowAdapter, // and registers them for handling events on the two // corresponding Button objects and the Frame object. // This code uses the abbreviated syntax for // anonymous classes and objects. This method is used // to activate the GUI after it is read from the disk // file. this.singButton.addActionListener( new ActionListener(){ public void actionPerformed(ActionEvent e){ System.out.println( "I am singing, Tra la la"); }//end actionPerformed() }//end ActionListener );//end addActionListener() this.whistleButton.addActionListener( new ActionListener(){ public void actionPerformed(ActionEvent e){ System.out.println( "I am whistling, Tweet Tweet Tweet"); }//end actionPerformed() }//end ActionListener );//end addActionListener() this.addWindowListener( new WindowAdapter(){ public void windowClosing(WindowEvent e){ System.exit(0);//terminate the program }//end windowClosing() }//end WindowAdapter );//end addWindowListener this.setSize(300,75); this.setVisible(true); this.repaint(); }//end activate() }//end class GUI //=======================================================// |
-end-