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 October 18, 1997 using the software and documentation in the JDK 1.1.3 download package along with the April 97 release of the BDK 1.0 download package.
A bound property notifies other objects when its value changes. Each time its value is changed, the property fires a PropertyChange event which contains the property name, old, and new values. Notification granularity is per bean, not per property. |
This bean class is examined with the Introspector and is tested with a test program designed specifically to exercise the ability of the bean to broadcast an event to a list of registered listener objects whenever the value of one of the properties changes.
Name of bean: Beans03 Class of bean: class Beans03 ==== Properties: ==== Name: preferredSize Type: class java.awt.Dimension Get method: public synchronized java.awt.Dimension Beans03.getPreferredSize() Set method: null Name: theDate Type: class java.util.Date Get method: null Set method: public synchronized void Beans03.setTheDate(java.util.Date) Name: theColor Type: class java.awt.Color Get method: public synchronized java.awt.Color Beans03.getTheColor() Set method: public synchronized void Beans03.setTheColor(java.awt.Color) ==== Events: ==== Event Name: propertyChange Add Method: public synchronized void Beans03.addPropertyChangeListener( java.beans.PropertyChangeListener) Remove Method: public synchronized void Beans03.removePropertyChangeListener( java.beans.PropertyChangeListener) Event Type: propertyChange ==== Methods: ==== makeRed setTheDate removePropertyChangeListener getTheColor setTheColor getPreferredSize addPropertyChangeListener makeBlue |
The bean class developed for this lesson has the following Bound
properties:
Name: theDate Type: class java.util.Date Get method: null Set method: public synchronized void Beans03.setTheDate(java.util.Date) Name: theColor Type: class java.awt.Color Get method: public synchronized java.awt.Color Beans03.getTheColor() Set method: public synchronized void Beans03.setTheColor(java.awt.Color) |
Objects that request to be added to the list must be of a class that implements the PropertyChangeListener interface and defines the propertyChange() method that is declared in that interface.
Whenever a value is assigned to the instance variables used to maintain these properties (regardless of whether or not it is a different value) an event is broadcast to all of the listener objects registered on the list.
The event is broadcast by invoking the propertyChange() method on all of the objects on the list. When this method is invoked on a listener object, an object of type PropertyChangeEvent is passed as a parameter.
The PropertyChangeEvent object passed as a parameter to the propertyChange() method in the listener objects contains the following information:
Notification of the listener objects takes place after the change in the property value has occurred. This bean class does not save the old value when it assigns a new value. As a result, it passes null as the old value of the changed property because the old value is no longer available when the listener objects are notified that a change has occurred.
The following methods are available to extract information from the object passed as a parameter. These methods are defined by the PropertyChangeEvent class or its superclass, EventObject:
This program was designed to be compiled and executed under JDK 1.1.3. It was tested using JDK 1.1.3 and the Apr97 version of the BDK 1.0 under Win95.
The purpose of this bean class is to illustrate bound properties.
This bean contains two bound properties: a Color property named theColor and a Date property named theDate. The Date property is a write-only property because no get method is provided for this property. (The bean class also contains a read-only property named preferredSize which resulted from providing that information for the benefit of the layout manager.)
Note that as of this writing in October of 1997, this bean class has not been tested in the BeanBox. It was tested using the test program named Beans03Test.
Any of the three methods in the following list can be invoked to assign
a new value to the property named theColor. Whenever any of these
methods are invoked, and after the new value is assigned to the property,
a PropertyChangeEvent is broadcast to all registered listener
objects.
setTheColor() makeRed() makeBlue() |
setTheDate() |
//The following instance variables are used to store // property values. protected Color myColor; protected Date myDate; //The following Vector is used to maintain a list of // listeners who request to be notified of changes in the // property values. protected Vector propChangeListeners = new Vector(); |
public synchronized void setTheColor(Color inColor){ myColor = inColor; this.setBackground(myColor); //notify property listeners of property change notifyPropertyChange("theColor"); }//end setTheColor() public synchronized Color getTheColor(){ return myColor; }//end getTheColor |
public synchronized void setTheDate(Date dateIn){ myDate = dateIn; //notify property listeners of property change notifyPropertyChange("theDate"); }//end setTheDate() |
public synchronized void makeBlue(){ myColor = Color.blue; this.setBackground(myColor); //notify property listeners of property change notifyPropertyChange("theColor"); }//end makeBlue() public synchronized void makeRed(){ myColor = Color.red; this.setBackground(myColor); //notify property listeners of property change notifyPropertyChange("theColor"); }//end makeRed() |
//Add a property change listener object to the list. public synchronized void addPropertyChangeListener( PropertyChangeListener listener){ //If the listener is not already registered, add it // to the list. if(!propChangeListeners.contains(listener)){ propChangeListeners.addElement(listener); }//end if }//end addPropertyChangeListener //-----------------------------------------------------// //Remove a property change listener from the list. public synchronized void removePropertyChangeListener( PropertyChangeListener listener){ //If the listener is on the list, remove it if(propChangeListeners.contains(listener)){ propChangeListeners.removeElement(listener); }//end if }//end removePropertyChangeListener |
In this case, there are only two bound properties. The incoming property name is used in a decision tree to determine which of the bound properties has changed in order to determine the values to be encapsulated in the PropertyChangeEvent object that is passed as a parameter when the registered listener objects are notified of the change.
Note that objects maintained in a Vector object are always of
type Object. This leads to the need to downcast the objects in the
list from Object to PropertyChangeListener.
protected void notifyPropertyChange( String changedProperty){ //Instantiate the event object containing information // about the property that has changed. PropertyChangeEvent event; if(changedProperty.compareTo("theColor") == 0) //Change was in theColor property event = new PropertyChangeEvent( this,changedProperty,null,myColor); else//Change was in the theDate property event = new PropertyChangeEvent( this,changedProperty,null,myDate); //Make a working copy of the list that cannot be // modified while objects on the list are being // notified of the change. Vector tempList; synchronized(this){ tempList = (Vector)propChangeListeners.clone(); }//end synchronized block //Notify all listener objects on the list. Note the // requirement to downcast the objects in the list from // Object to PropertyChangeListener. for(int cnt = 0; cnt < tempList.size();cnt++){ PropertyChangeListener theListener = (PropertyChangeListener)tempList.elementAt(cnt); //Invoke the propertyChange() method on theListener theListener.propertyChange(event); }//end for loop }//end notifyPropertyChange }//end class Beans03.java |
/*File Beans03.java Copyright 1997, R.G.Baldwin This program was designed to be compiled and executed under JDK 1.1.3 or later. The main purpose of this program is to illustrate the use of "bound" properties in Beans. This is a "bean" class that satisfies the interface requirements for beans using design patterns. This bean class has two properties named theColor and theDate. The current value of the property named theColor is stored in the instance variable named myColor. The current value of the property named theDate is stored in the instance variable named myDate. theDate is a write-only property because it has a "set" method but does not have a "get" method. The program maintains a list of objects that request to be notified whenever there is a change in the value of either of the properties. Whenever the value of either property changes, all of the objects on the list are notified of the change by invoking their propertyChange() method and passing an object of type PropertyChangeEvent as a parameter. Objects that request to be added to the list must be of a class that implements the PropertyChangeListener interface and defines the propertyChange() method that is declared in that interface. The PropertyChangeEvent object passed as a parameter to the propertyChange() method in the listener objects contains the following information: Object source, //the bean object String propertyName, //the name of the changed property Object oldValue, //the old value of the changed property Object newValue //the new value of the changed property This program doesn't save the old value and therefore passes null as the old value of the changed property because the old value is not available when the listener objects are notified. The following methods are available to extract information from the object passed as a parameter. These methods are defined by the PropertyChangeEvent class or its superclass named EventObject: public Object getSource(); public Object getNewValue(); public Object getOldValue(); public String getPropertyName; public void setPropagationId(); public Object getPropagationId; Apparently the PropagationID is reserved for future use. The program was compiled and tested under JDK 1.1.3 and Win95. Another program named Beans03Test.java was used to test the bean. It was not tested in the BeanBox. //=======================================================// */ import java.awt.event.*; import java.awt.*; import java.io.Serializable; import java.util.*; import java.beans.*; //=======================================================// //All beans should implement the Serializable interface public class Beans03 extends Canvas implements Serializable{ //The following instance variables are used to store // property values. protected Color myColor; protected Date myDate; //The following Vector is used to maintain a list of // listeners who request to be notified of changes in the // property values. protected Vector propChangeListeners = new Vector(); //-----------------------------------------------------// public Beans03(){//constructor //This bean is a visible square that is initialized to // yellow and can then be changed to green, red, and // blue by invoking methods of the class. myColor = Color.yellow; setBackground(myColor); }//end constructor //-----------------------------------------------------// //This method defines the preferred display size of the // bean object. public synchronized Dimension getPreferredSize(){ return new Dimension(50,50); }//end getPreferredSize() //-----------------------------------------------------// //The following "set" and "get" methods in conjunction // with the instance variable named myColor constitute a // property named theColor. public synchronized void setTheColor(Color inColor){ myColor = inColor; this.setBackground(myColor); //notify property listeners of property change notifyPropertyChange("theColor"); }//end setTheColor() public synchronized Color getTheColor(){ return myColor; }//end getTheColor //-----------------------------------------------------// //The following "set" method in conjunction with the // instance variable named myDate constitute a write-only // property named theDate. public synchronized void setTheDate(Date dateIn){ myDate = dateIn; //notify property listeners of property change notifyPropertyChange("theDate"); }//end setTheDate() //-----------------------------------------------------// //The following two methods are exposed to the builder // tool as accessible methods. public synchronized void makeBlue(){ myColor = Color.blue; this.setBackground(myColor); //notify property listeners of property change notifyPropertyChange("theColor"); }//end makeBlue() public synchronized void makeRed(){ myColor = Color.red; this.setBackground(myColor); //notify property listeners of property change notifyPropertyChange("theColor"); }//end makeRed() //-----------------------------------------------------// //The following two methods are used to maintain a list // of listener objects who request to be notified of // changes to the properties or who request to be removed // from the list. //Add a property change listener object to the list. public synchronized void addPropertyChangeListener( PropertyChangeListener listener){ //If the listener is not already registered, add it // to the list. if(!propChangeListeners.contains(listener)){ propChangeListeners.addElement(listener); }//end if }//end addPropertyChangeListener //Remove a property change listener from the list. public synchronized void removePropertyChangeListener( PropertyChangeListener listener){ //If the listener is on the list, remove it if(propChangeListeners.contains(listener)){ propChangeListeners.removeElement(listener); }//end if }//end removePropertyChangeListener //-----------------------------------------------------// //The following method is used to notify listener // objects of changes in the properties. The incoming // parameter is the name of the property that has // changed. protected void notifyPropertyChange( String changedProperty){ //Instantiate the event object containing information // about the property that has changed. PropertyChangeEvent event; if(changedProperty.compareTo("theColor") == 0) //Change was in theColor property event = new PropertyChangeEvent( this,changedProperty,null,myColor); else//Change was in the theDate property event = new PropertyChangeEvent( this,changedProperty,null,myDate); //Make a working copy of the list that cannot be // modified while objects on the list are being // notified of the change. Vector tempList; synchronized(this){ tempList = (Vector)propChangeListeners.clone(); }//end synchronized block //Notify all listener objects on the list. Note the // requirement to cast the objects in the list from // Object to PropertyChangeListener. for(int cnt = 0; cnt < tempList.size();cnt++){ PropertyChangeListener theListener = (PropertyChangeListener)tempList.elementAt(cnt); //Invoke the propertyChange() method on theListener theListener.propertyChange(event); }//end for loop }//end notifyPropertyChange }//end class Beans03.java //=======================================================// |
The purpose of this program is to provide the ability to test the bean class named Beans03 in a Frame.
A Beans03 object is placed in the frame along with five buttons. The visual manifestation of the bean object is a colored square.
Two of the buttons exercise the "get" and "set" methods used to get and set the Color value stored in the property named theColor.
One button exercises the "set" method used to set the date and time in a write-only Date property named theDate.
Two of the buttons invoke the makeRed() and makeBlue() methods of the bean which modify the value of the property named theColor.
Two listener objects are instantiated and registered to be notified by the bean whenever there is a change in the value of either of the bound properties. Actually the objects are notified whenever a value is assigned to the instance variables that maintain the property values regardless of whether or not the new value is different from the old value.
For those cases where information is returned from the bean, it is displayed on the standard output device.
Clicking the button labeled "Set theColor property" produced the following output on the screen. As you can see, the two different listener objects were notified of the same change in the property named theColor.
In this case, the value of the theColor property was changed to green as indicated by "g=255". The actual color is specified by percentage contributions from red, green, and blue, where the maximum contribution of any one of the primary colors is 255 and the minimum contribution is 0. In this case, both red and blue are showing a contribution of 0.
The Old property value is shown as null because this particular
bean class doesn't save and return the value of the property that
existed before the change occurred. The event doesn't happen until after
the change has occurred and the old value is no longer available at that
point in time.
FirstListener notified of change Property change source: Beans03[canvas0,31,33,50x50] Property name: theColor New property value: java.awt.Color[r=0,g=255,b=0] Old property value: null SecondListener notified of change Property change source: Beans03[canvas0,31,33,50x50] Property name: theColor New property value: java.awt.Color[r=0,g=255,b=0] Old property value: null |
java.awt.Color[r=0,g=255,b=0] |
FirstListener notified of change Property change source: Beans03[canvas0,31,33,50x50] Property name: theColor New property value: java.awt.Color[r=255,g=0,b=0] Old property value: null SecondListener notified of change Property change source: Beans03[canvas0,31,33,50x50] Property name: theColor New property value: java.awt.Color[r=255,g=0,b=0] Old property value: null |
FirstListener notified of change Property change source: Beans03[canvas0,31,33,50x50] Property name: theColor New property value: java.awt.Color[r=0,g=0,b=255] Old property value: null SecondListener notified of change Property change source: Beans03[canvas0,31,33,50x50] Property name: theColor New property value: java.awt.Color[r=0,g=0,b=255] Old property value: null |
FirstListener notified of change Property change source: Beans03[canvas0,31,33,50x50] Property name: theDate New property value: Sat Oct 18 10:24:49 CDT 1997 Old property value: null SecondListener notified of change Property change source: Beans03[canvas0,31,33,50x50] Property name: theDate New property value: Sat Oct 18 10:24:49 CDT 1997 Old property value: null |
The beginning of the interesting code appears at the point where we
register action listener objects for all of the buttons on the test panel.
Although this code is straightforward, it will be useful to show it here
to establish the basis for further discussion.
buttonToSetTheColor.addActionListener( new SetTheColorListener(myBean)); buttonToGetTheColor.addActionListener( new GetTheColorListener(myBean)); buttonToInvokeRedMethod.addActionListener( new RedActionListener(myBean)); buttonToInvokeBlueMethod.addActionListener( new BlueActionListener(myBean)); buttonToSetTheDate.addActionListener( new DateActionListener(myBean)); |
MyPropertyChangeListener firstListener = new MyPropertyChangeListener(); //Store an identifying name in the listener object firstListener.setTheID("FirstListener"); myBean.addPropertyChangeListener(firstListener); MyPropertyChangeListener secondListener = new MyPropertyChangeListener(); //Store an identifying name in the listener object secondListener.setTheID("SecondListener"); myBean.addPropertyChangeListener(secondListener); |
// myBean.removePropertyChangeListener(firstListener); // myBean.removePropertyChangeListener(secondListener); |
class DateActionListener implements ActionListener{ Beans03 myBean;//save a reference to the bean here DateActionListener(Beans03 inBean){//constructor myBean = inBean;//save a reference to the bean }//end constructor public void actionPerformed(ActionEvent e){ //Store the current date and time in the bean property // named theDate. myBean.setTheDate(new Date()); }//end actionPerformed() }//end class DateActionListener |
class SetTheColorListener implements ActionListener{ Beans03 myBean;//save a reference to the bean here SetTheColorListener(Beans03 inBean){//constructor myBean = inBean;//save a reference to the bean }//end constructor public void actionPerformed(ActionEvent e){ myBean.setTheColor(Color.green); }//end actionPerformed() }//end class SetTheColorListener |
class GetTheColorListener implements ActionListener{ Beans03 myBean;//save a reference to the bean here GetTheColorListener(Beans03 inBean){//constructor myBean = inBean;//save reference to the bean }//end constructor public void actionPerformed(ActionEvent e){ //Display value of the theColor property on the // standard output device. System.out.println(myBean.getTheColor().toString()); }//end actionPerformed() }//end class GetTheColorListener |
class RedActionListener implements ActionListener{ Beans03 myBean;//save a reference to the bean here RedActionListener(Beans03 inBean){//constructor myBean = inBean;//save the reference to the bean }//end constructor public void actionPerformed(ActionEvent e){ myBean.makeRed(); }//end actionPerformed() }//end class RedActionListener //-------------------------------------------------------// class BlueActionListener implements ActionListener{ Beans03 myBean;//save a reference to the bean here BlueActionListener(Beans03 inBean){//constructor myBean = inBean;//save the reference to the bean }//end constructor public void actionPerformed(ActionEvent e){ myBean.makeBlue(); }//end actionPerformed() }//end class BlueActionListener |
class MyPropertyChangeListener implements PropertyChangeListener{ String theID; //store listener object ID here void setTheID(String nameIn){ //method to save the ID of the object theID = nameIn; }//end setTheID() public void propertyChange(PropertyChangeEvent event){ //Extract and display information about the event System.out.println(theID + " notified of change"); System.out.println("Property change source: " + event.getSource()); System.out.println("Property name: " + event.getPropertyName()); System.out.println("New property value: " + event.getNewValue()); System.out.println("Old property value: " + event.getOldValue()); System.out.println();//blank line }//end propertyChange() }//end MyPropertyChangeListener class |
A consolidated listing of the complete test program is contained in the next section.
/*File Beans03Test.java Copyright 1997, R.G.Baldwin This program was designed to be compiled and executed under JDK 1.1.3 or later. The purpose of this program is to provide the ability to test the bean class named Beans03.class in a Frame. A Beans03 object is placed in the frame along with five buttons. The visual manifestation of the Bean object is a colored square. Two of the buttons exercise the "get" and "set" methods used to get and set the color value stored in the property named theColor. One button exercises the "set" method used to set the date and time in a write-only property named theDate. Two of the buttons invoke the makeRed() and makeBlue() methods of the Bean which modify the value of the property named theColor. Two listener objects are instantiated and registered to be notified by the bean whenever there is a change in the value of either of the properties. Actually the objects are notified whenever a value is assigned to the instance variables that maintain the property values regardless of whether or not the new value is different from the old value. For those cases where information is returned from the Bean, it is displayed on the standard output device. The program was tested using JDK 1.1.3 under Win95. Clicking the button labeled "Set theColor property" produced the following output on the screen. As you can see, the two different listener objects were notified of the same change in the property named theColor. In this case, the value of theColor property was changed to green. FirstListener notified of change Property change source: Beans03[canvas0,31,33,50x50] Property name: theColor New property value: java.awt.Color[r=0,g=255,b=0] Old property value: null SecondListener notified of change Property change source: Beans03[canvas0,31,33,50x50] Property name: theColor New property value: java.awt.Color[r=0,g=255,b=0] Old property value: null Clicking the button labeled "Get theColor property" produced the following output on the screen. Since this action didn't cause the property values to change, the listener objects were not notified of the action. java.awt.Color[r=0,g=255,b=0] Clicking the button labeled "Invoke the makeRed Method" produced the following output on the screen. Again both listener objects were notified of the change in the property named theColor with the new value being red. FirstListener notified of change Property change source: Beans03[canvas0,31,33,50x50] Property name: theColor New property value: java.awt.Color[r=255,g=0,b=0] Old property value: null SecondListener notified of change Property change source: Beans03[canvas0,31,33,50x50] Property name: theColor New property value: java.awt.Color[r=255,g=0,b=0] Old property value: null Clicking the button labeled "Invoke the makeBlue Method" produced the following output on the screen similar to that produced by invoking the makeRed() method described above. FirstListener notified of change Property change source: Beans03[canvas0,31,33,50x50] Property name: theColor New property value: java.awt.Color[r=0,g=0,b=255] Old property value: null SecondListener notified of change Property change source: Beans03[canvas0,31,33,50x50] Property name: theColor New property value: java.awt.Color[r=0,g=0,b=255] Old property value: null Finally, clicking the button labeled "Set theDate property" produced the following output on the screen. In this case, both listener objects were notified and the information encapsulated in the event object identified the changed property as the property named theDate with a new value as shown. FirstListener notified of change Property change source: Beans03[canvas0,31,33,50x50] Property name: theDate New property value: Sat Oct 18 10:24:49 CDT 1997 Old property value: null SecondListener notified of change Property change source: Beans03[canvas0,31,33,50x50] Property name: theDate New property value: Sat Oct 18 10:24:49 CDT 1997 Old property value: null */ import java.awt.*; import java.awt.event.*; import java.beans.*; import java.util.*; //=======================================================// public class Beans03Test extends Frame{ public static void main(String[] args){ new Beans03Test(); }//end main //-----------------------------------------------------// public Beans03Test(){//constructor setTitle("Copyright 1997, R.G.Baldwin"); setLayout(new FlowLayout()); //instantiate a Bean object Beans03 myBean = new Beans03(); add(myBean);//Add it to the Frame //Instantiate several test buttons Button buttonToSetTheColor = new Button("Set theColor property"); Button buttonToGetTheColor = new Button("Get theColor property"); Button buttonToInvokeRedMethod = new Button("Invoke makeRed Method"); Button buttonToInvokeBlueMethod = new Button("Invoke makeBlue Method"); Button buttonToSetTheDate = new Button("Set theDate property"); //Add the test buttons to the frame add(buttonToSetTheColor); add(buttonToGetTheColor); add(buttonToInvokeRedMethod); add(buttonToInvokeBlueMethod); add(buttonToSetTheDate); //Size the frame and make it visible setSize(250,350); setVisible(true); //Register action listener objects for all the test // buttons buttonToSetTheColor.addActionListener( new SetTheColorListener(myBean)); buttonToGetTheColor.addActionListener( new GetTheColorListener(myBean)); buttonToInvokeRedMethod.addActionListener( new RedActionListener(myBean)); buttonToInvokeBlueMethod.addActionListener( new BlueActionListener(myBean)); buttonToSetTheDate.addActionListener( new DateActionListener(myBean)); //Instantiate and register two PropertyChangeListener // objects to listen for changes in the bean's // properties. MyPropertyChangeListener firstListener = new MyPropertyChangeListener(); //Store an identifying name in the listener object firstListener.setTheID("FirstListener"); myBean.addPropertyChangeListener(firstListener); MyPropertyChangeListener secondListener = new MyPropertyChangeListener(); //Store an identifying name in the listener object secondListener.setTheID("SecondListener"); myBean.addPropertyChangeListener(secondListener); //The following statements can be activated to confirm // proper operation of the removePropertyChangeListener // interface of the bean object. When one or the other // of these statements is activated, and the program is // recompiled, only the other listener object is // notified of changes in the values of properties // in the bean. // myBean.removePropertyChangeListener(firstListener); // myBean.removePropertyChangeListener(secondListener); //terminate when Frame is closed this.addWindowListener(new Terminate()); }//end constructor }//end class Beans03Test //=======================================================// //The following class is used to instantiate objects to // be registered to listen to one of the buttons on the // test panel. When the setTheDate button is pressed, the // theDate property is set to the current date and time. class DateActionListener implements ActionListener{ Beans03 myBean;//save a reference to the bean here DateActionListener(Beans03 inBean){//constructor myBean = inBean;//save a reference to the bean }//end constructor public void actionPerformed(ActionEvent e){ //Store the current date and time in the bean property // named theDate. myBean.setTheDate(new Date()); }//end actionPerformed() }//end class DateActionListener //=======================================================// //The following two classes are used to instantiate objects // to be registered to listen to two of the buttons on the // test panel. // When the setTheColor button is pressed, the theColor // property is set to green. // When the getTheColor button is pressed, the current // color is displayed on the standard output device. class SetTheColorListener implements ActionListener{ Beans03 myBean;//save a reference to the bean here SetTheColorListener(Beans03 inBean){//constructor myBean = inBean;//save a reference to the bean }//end constructor public void actionPerformed(ActionEvent e){ myBean.setTheColor(Color.green); }//end actionPerformed() }//end class SetTheColorListener //-------------------------------------------------------// class GetTheColorListener implements ActionListener{ Beans03 myBean;//save a reference to the bean here GetTheColorListener(Beans03 inBean){//constructor myBean = inBean;//save reference to the bean }//end constructor public void actionPerformed(ActionEvent e){ //Display value of the theColor property on the // standard output device. System.out.println(myBean.getTheColor().toString()); }//end actionPerformed() }//end class GetTheColorListener //=======================================================// //The following two classes are used to instantiate objects // to be registered to listen to two of the buttons on the // test panel. When the corresponding the buttons are // pressed, these objects invoke methods of the bean under // test. The first class invokes the makeRed() method and // the second class invokes the makeBlue() method. class RedActionListener implements ActionListener{ Beans03 myBean;//save a reference to the bean here RedActionListener(Beans03 inBean){//constructor myBean = inBean;//save the reference to the bean }//end constructor public void actionPerformed(ActionEvent e){ myBean.makeRed(); }//end actionPerformed() }//end class RedActionListener //-------------------------------------------------------// class BlueActionListener implements ActionListener{ Beans03 myBean;//save a reference to the bean here BlueActionListener(Beans03 inBean){//constructor myBean = inBean;//save the reference to the bean }//end constructor public void actionPerformed(ActionEvent e){ myBean.makeBlue(); }//end actionPerformed() }//end class BlueActionListener //=======================================================// //The following class is used to instantiate objects that // will be bound to the bean in such a way as to be // notified of changes in the property values in the bean // object. When notified of such changes, code in the // propertyChange() method of this class extracts and // displays information about the bean and the properties. class MyPropertyChangeListener implements PropertyChangeListener{ String theID; //store listener object ID here void setTheID(String nameIn){ //method to save the ID of the object theID = nameIn; }//end setTheID() public void propertyChange(PropertyChangeEvent event){ //Extract and display information about the event System.out.println(theID + " notified of change"); System.out.println("Property change source: " + event.getSource()); System.out.println("Property name: " + event.getPropertyName()); System.out.println("New property value: " + event.getNewValue()); System.out.println("Old property value: " + event.getOldValue()); System.out.println();//blank line }//end propertyChange() }//end MyPropertyChangeListener class //=======================================================// class Terminate extends WindowAdapter{ public void windowClosing(WindowEvent e){ //terminate the program when the window is closed System.exit(0); }//end windowClosing }//end class Terminate //=======================================================// |
Java provides the java.beans.PropertyChangeSupport
class that can be used to handle the maintenance of the registration list
as well as the task of firing events to the registered listener objects
on that list. A description of the constructor and methods of the class
is shown below.
Constructor public PropertyChangeSupport(Object sourceBean) Methods public synchronized void addPropertyChangeListener( PropertyChangeListener listener) Adds a PropertyChangeListener to the listener list. Parameters: listener - The PropertyChangeListener to be added public synchronized void removePropertyChangeListener( PropertyChangeListener listener) Removes a PropertyChangeListener from the listener list. Parameters: listener - The PropertyChangeListener to be removed public void firePropertyChange(String propertyName, Object oldValue, Object newValue) Reports a bound property update to any registered listeners. No event is fired if old and new are equal and non-null. Parameters: propertyName - The name of the property that was changed. oldValue - The old value of the property. newValue - The new value of the property. |
The requirement to instantiate the support class into a separate object resulted in a small amount of extra programming effort. In particular, it was necessary to define add and remove method shells for the bean class and then pass the listener object parameters received by those method shells to the add and remove methods in the support object. If the bean class extended the support class, the add and remove methods of the support class would be inherited into the bean class.
Complete listings of the revised bean class
and the corresponding test program follow. Important information is included
in the comments in these two programs.
/*File Beans05.java Copyright 1997, R.G.Baldwin This program was designed to be compiled and executed under JDK 1.1.3 or later. This bean class is designed to replicate the functionality of the bean class named Beans04 by making use of the support class named java.beans.PropertyChangeSupport to reduce the level of programming effort required. This support class provides methods for maintaining the list of registered PropertyChange listeners and for firing events to all of the listener objects on that list, thus eliminating the need to code those capabilities by hand as was done with Beans04. The support class can either be extended or instantiated. In this case, because this bean class was already extending the Canvas class and multiple inheritance is not allowed, the support class was instantiated. This made it necessary to do a little extra work in providing bean interface methods to add and remove listener objects and then to call the corresponding methods in the support class object passing the listener references as parameters. //=======================================================// */ import java.awt.event.*; import java.awt.*; import java.io.Serializable; import java.util.*; import java.beans.*; //=======================================================// //All beans should implement the Serializable interface public class Beans05 extends Canvas implements Serializable{ //The following instance variables are used to store // property values. protected Color myColor; protected Date myDate; //The following reference variable is used to access // the list maintenance and event firing capabilities // of the PropertyChangeSupport class, an object of // which is instantiated in the constructor. PropertyChangeSupport supportObj; //-----------------------------------------------------// public Beans05(){//constructor //This bean is a visible square that is initialized to // yellow and can then be changed to green, red, and // blue by invoking methods of the class. myColor = Color.yellow; setBackground(myColor); //Instantiate an object of the support class to handle // list maintenance and event firing tasks. The // constructor requires this object as the source of // the events. supportObj = new PropertyChangeSupport(this); }//end constructor //-----------------------------------------------------// //This method defines the preferred display size of the // bean object. public synchronized Dimension getPreferredSize(){ return new Dimension(50,50); }//end getPreferredSize() //-----------------------------------------------------// //The following "set" and "get" methods in conjunction // with the instance variable named myColor constitute a // property named theColor. public synchronized void setTheColor(Color inColor){ Color oldColor = myColor; myColor = inColor; this.setBackground(myColor); //notify property listeners of property change if(!myColor.equals(oldColor)) notifyPropertyChange("theColor"); }//end setTheColor() public synchronized Color getTheColor(){ return myColor; }//end getTheColor //-----------------------------------------------------// //The following "set" method in conjunction with the // instance variable named myDate constitute a write-only // property named theDate. public synchronized void setTheDate(Date dateIn){ Date oldDate = myDate; myDate = dateIn; //notify property listeners of property change if(!myDate.equals(oldDate)) notifyPropertyChange("theDate"); }//end setTheDate() //-----------------------------------------------------// //The following two methods are exposed to the builder // tool as accessible methods. public synchronized void makeBlue(){ Color oldColor = myColor; myColor = Color.blue; this.setBackground(myColor); //notify property listeners of property change if(!myColor.equals(oldColor)) notifyPropertyChange("theColor"); }//end makeBlue() public synchronized void makeRed(){ Color oldColor = myColor; myColor = Color.red; this.setBackground(myColor); //notify property listeners of property change if(!myColor.equals(oldColor)) notifyPropertyChange("theColor"); }//end makeRed() //-----------------------------------------------------// //The following two methods are used to maintain a list // of listener objects who request to be notified of // changes to the properties or who request to be removed // from the list. Note that these two methods do // nothing more than to accept a reference to the // object requesting registration and pass that reference // to the list maintenance facility provided by an object // of the PropertyChangeSupport class. //Add a property change listener object to the list. public synchronized void addPropertyChangeListener( PropertyChangeListener listener){ supportObj.addPropertyChangeListener(listener); }//end addPropertyChangeListener //-------------------------------------------------------// //Remove a property change listener from the list. public synchronized void removePropertyChangeListener( PropertyChangeListener listener){ supportObj.removePropertyChangeListener(listener); }//end removePropertyChangeListener() //-----------------------------------------------------// //The following method is used to notify listener // objects of changes in the properties. The incoming // parameter is the name of the property that has // changed. Note that this method makes use of the // event-firing capability of an object of the // PropertyChangeSupport class. protected void notifyPropertyChange( String changedProperty){ if(changedProperty.compareTo("theColor") == 0) //Change was in theColor property supportObj.firePropertyChange( changedProperty,null,myColor); else//Change was in the theDate property supportObj.firePropertyChange( changedProperty,null,myDate); }//end notifyPropertyChange() }//end class Beans05.java //=======================================================// |
/*File Beans05Test.java Copyright 1997, R.G.Baldwin This program was designed to be compiled and executed under JDK 1.1.3 or later. The purpose of this program is to provide the ability to test the bean class named Beans05.class in a Frame. See the comments in the file named Beans05.java to understand how this test program and the bean differ from the test program named Beans04Test and its corresponding bean. Briefly, this pair of programs replicates the Beans04 pair in functionality. However, Beans05 uses a support class named java.beans.PropertyChangedSupport to reduce the programming effort required for the bean. See the program named Beans04Test for an operational description of this program along with sample output produced by the program. */ import java.awt.*; import java.awt.event.*; import java.beans.*; import java.util.*; //=======================================================// public class Beans05Test extends Frame{ public static void main(String[] args){ new Beans05Test(); }//end main //-----------------------------------------------------// public Beans05Test(){//constructor setTitle("Copyright 1997, R.G.Baldwin"); setLayout(new FlowLayout()); //instantiate a Bean object Beans05 myBean = new Beans05(); add(myBean);//Add it to the Frame //Instantiate several test buttons Button buttonToSetTheColor = new Button("Set theColor property"); Button buttonToGetTheColor = new Button("Get theColor property"); Button buttonToInvokeRedMethod = new Button("Invoke makeRed Method"); Button buttonToInvokeBlueMethod = new Button("Invoke makeBlue Method"); Button buttonToSetTheDate = new Button("Set theDate property"); //Add the test buttons to the frame add(buttonToSetTheColor); add(buttonToGetTheColor); add(buttonToInvokeRedMethod); add(buttonToInvokeBlueMethod); add(buttonToSetTheDate); //Size the frame and make it visible setSize(250,350); setVisible(true); //Register action listener objects for all the test // buttons buttonToSetTheColor.addActionListener( new SetTheColorListener(myBean)); buttonToGetTheColor.addActionListener( new GetTheColorListener(myBean)); buttonToInvokeRedMethod.addActionListener( new RedActionListener(myBean)); buttonToInvokeBlueMethod.addActionListener( new BlueActionListener(myBean)); buttonToSetTheDate.addActionListener( new DateActionListener(myBean)); //Instantiate and register two PropertyChangeListener // objects to listen for changes in the bean's // properties. MyPropertyChangeListener firstListener = new MyPropertyChangeListener(); //Store an identifying name in the listener object firstListener.setTheID("FirstListener"); myBean.addPropertyChangeListener(firstListener); MyPropertyChangeListener secondListener = new MyPropertyChangeListener(); //Store an identifying name in the listener object secondListener.setTheID("SecondListener"); myBean.addPropertyChangeListener(secondListener); //The following statements can be activated to confirm // proper operation of the removePropertyChangeListener // interface of the bean object. When one or the other // of these statements is activated, and the program is // recompiled, only the other listener object is // notified of changes in the values of properties // in the bean. // myBean.removePropertyChangeListener(firstListener); // myBean.removePropertyChangeListener(secondListener); //terminate when Frame is closed this.addWindowListener(new Terminate()); }//end constructor }//end class Beans05Test //=======================================================// //The following class is used to instantiate objects to // be registered to listen to one of the buttons on the // test panel. When the setTheDate button is pressed, the // theDate property is set to the current date and time. class DateActionListener implements ActionListener{ Beans05 myBean;//save a reference to the bean here DateActionListener(Beans05 inBean){//constructor myBean = inBean;//save a reference to the bean }//end constructor public void actionPerformed(ActionEvent e){ //Store the current date and time in the bean property // named theDate. myBean.setTheDate(new Date()); }//end actionPerformed() }//end class DateActionListener //=======================================================// //The following two classes are used to instantiate objects // to be registered to listen to two of the buttons on the // test panel. // When the setTheColor button is pressed, the theColor // property is set to green. // When the getTheColor button is pressed, the current // color is displayed on the standard output device. class SetTheColorListener implements ActionListener{ Beans05 myBean;//save a reference to the bean here SetTheColorListener(Beans05 inBean){//constructor myBean = inBean;//save a reference to the bean }//end constructor public void actionPerformed(ActionEvent e){ myBean.setTheColor(Color.green); }//end actionPerformed() }//end class SetTheColorListener //-------------------------------------------------------// class GetTheColorListener implements ActionListener{ Beans05 myBean;//save a reference to the bean here GetTheColorListener(Beans05 inBean){//constructor myBean = inBean;//save reference to the bean }//end constructor public void actionPerformed(ActionEvent e){ //Display value of the theColor property on the // standard output device. System.out.println(myBean.getTheColor().toString()); }//end actionPerformed() }//end class GetTheColorListener //=======================================================// //The following two classes are used to instantiate objects // to be registered to listen to two of the buttons on the // test panel. When the corresponding the buttons are // pressed, these objects invoke methods of the bean under // test. The first class invokes the makeRed() method and // the second class invokes the makeBlue() method. class RedActionListener implements ActionListener{ Beans05 myBean;//save a reference to the bean here RedActionListener(Beans05 inBean){//constructor myBean = inBean;//save the reference to the bean }//end constructor public void actionPerformed(ActionEvent e){ myBean.makeRed(); }//end actionPerformed() }//end class RedActionListener //-------------------------------------------------------// class BlueActionListener implements ActionListener{ Beans05 myBean;//save a reference to the bean here BlueActionListener(Beans05 inBean){//constructor myBean = inBean;//save the reference to the bean }//end constructor public void actionPerformed(ActionEvent e){ myBean.makeBlue(); }//end actionPerformed() }//end class BlueActionListener //=======================================================// //The following class is used to instantiate objects that // will be bound to the bean in such a way as to be // notified of changes in the property values in the bean // object. When notified of such changes, code in the // propertyChange() method of this class extracts and // displays information about the bean and the properties. class MyPropertyChangeListener implements PropertyChangeListener{ String theID; //store listener object ID here void setTheID(String nameIn){ //method to save the ID of the object theID = nameIn; }//end setTheID() public void propertyChange(PropertyChangeEvent event){ //Extract and display information about the event System.out.println(theID + " notified of change"); System.out.println("Property change source: " + event.getSource()); System.out.println("Property name: " + event.getPropertyName()); System.out.println("New property value: " + event.getNewValue()); System.out.println("Old property value: " + event.getOldValue()); System.out.println();//blank line }//end propertyChange() }//end MyPropertyChangeListener class //=======================================================// class Terminate extends WindowAdapter{ public void windowClosing(WindowEvent e){ //terminate the program when the window is closed System.exit(0); }//end windowClosing }//end class Terminate //=======================================================// |
Without viewing the following solution, upgrade that bean class to produce a new bean class that will broadcast a PropertyChangeEvent only if the new value is different from the old value.
Provide a bean test program to demonstrate proper operation of the new bean class.
A - See the following bean program and test program.
Bean program follows:
/*File Beans04.java Copyright 1997, R.G.Baldwin This program was designed to be compiled and executed under JDK 1.1.3 or later. The bean class named Beans03 broadcasts a PropertyChange Event whenever a new value is assigned to one of the instance variables used to maintain the property values regardless of whether the new value is different from, or the same as the old value. Upgrade that bean class to produce a new bean class that will refrain from broadcasting a PropertyChangeEvent if the new value is the same as the old value. Provide a bean test program to demonstrate proper operation of the new bean class. The main purpose of this program is to illustrate the use of "bound" properties in Beans. This is a "bean" class that satisfies the interface requirements for beans using design patterns. This bean class has two properties named theColor and theDate. The current value of the property named theColor is stored in the instance variable named myColor. The current value of the property named theDate is stored in the instance variable named myDate. theDate is a write-only property because it has a "set" method but does not have a "get" method. The program maintains a list of objects that request to be notified whenever there is a change in the value of either of the properties. Whenever the value of either property changes, all of the objects on the list are notified of the change by invoking their propertyChange() method and passing an object of type PropertyChangeEvent as a parameter. Objects that request to be added to the list must be of a class that implements the PropertyChangeListener interface and defines the propertyChange() method that is declared in that interface. The PropertyChangeEvent object passed as a parameter to the propertyChange() method in the listener objects contains the following information: Object source, //the bean object String propertyName, //the name of the changed property Object oldValue, //the old value of the changed property Object newValue //the new value of the changed property This program doesn't save the old value and therefore passes null as the old value of the changed property because the old value is not available when the listener objects are notified. The following methods are available to extract information from the object passed as a parameter. These methods are defined by the PropertyChangeEvent class or its superclass named EventObject: public Object getSource(); public Object getNewValue(); public Object getOldValue(); public String getPropertyName; public void setPropagationId(); public Object getPropagationId; Apparently the PropagationID is reserved for future use. The program was compiled and tested under JDK 1.1.3 and Win95. Another program named Beans03Test.java was used to test the bean. It was not tested in the BeanBox. //=======================================================// */ import java.awt.event.*; import java.awt.*; import java.io.Serializable; import java.util.*; import java.beans.*; //=======================================================// //All beans should implement the Serializable interface public class Beans04 extends Canvas implements Serializable{ //The following instance variables are used to store // property values. protected Color myColor; protected Date myDate; //The following vector is used to maintain a list of // listeners who request to be notified of changes in the // property values. protected Vector propChangeListeners = new Vector(); //-----------------------------------------------------// public Beans04(){//constructor //This bean is a visible square that is initialized to // yellow and can then be changed to green, red, and // blue by invoking methods of the class. myColor = Color.yellow; setBackground(myColor); }//end constructor //-----------------------------------------------------// //This method defines the preferred display size of the // bean object. public synchronized Dimension getPreferredSize(){ return new Dimension(50,50); }//end getPreferredSize() //-----------------------------------------------------// //The following "set" and "get" methods in conjunction // with the instance variable named myColor constitute a // property named theColor. public synchronized void setTheColor(Color inColor){ Color oldColor = myColor; myColor = inColor; this.setBackground(myColor); //notify property listeners of property change if(!myColor.equals(oldColor)) notifyPropertyChange("theColor"); }//end setTheColor() public synchronized Color getTheColor(){ return myColor; }//end getTheColor //-----------------------------------------------------// //The following "set" method in conjunction with the // instance variable named myDate constitute a write-only // property named theDate. public synchronized void setTheDate(Date dateIn){ Date oldDate = myDate; myDate = dateIn; //notify property listeners of property change if(!myDate.equals(oldDate)) notifyPropertyChange("theDate"); }//end setTheDate() //-----------------------------------------------------// //The following two methods are exposed to the builder // tool as accessible methods. public synchronized void makeBlue(){ Color oldColor = myColor; myColor = Color.blue; this.setBackground(myColor); //notify property listeners of property change if(!myColor.equals(oldColor)) notifyPropertyChange("theColor"); }//end makeBlue() public synchronized void makeRed(){ Color oldColor = myColor; myColor = Color.red; this.setBackground(myColor); //notify property listeners of property change if(!myColor.equals(oldColor)) notifyPropertyChange("theColor"); }//end makeRed() //-----------------------------------------------------// //The following two methods are used to maintain a list // of listener objects who request to be notified of // changes to the properties or who request to be removed // from the list. //Add a property change listener object to the list. public synchronized void addPropertyChangeListener( PropertyChangeListener listener){ //If the listener is not already registered, add it // to the list. if(!propChangeListeners.contains(listener)){ propChangeListeners.addElement(listener); }//end if }//end addPropertyChangeListener //Remove a property change listener from the list. public synchronized void removePropertyChangeListener( PropertyChangeListener listener){ //If the listener is on the list, remove it if(propChangeListeners.contains(listener)){ propChangeListeners.removeElement(listener); }//end if }//end removePropertyChangeListener //-----------------------------------------------------// //The following method is used to notify listener // objects of changes in the properties. The incoming // parameter is the name of the property that has // changed. protected void notifyPropertyChange( String changedProperty){ //Instantiate the event object containing information // about the property that has changed. PropertyChangeEvent event; if(changedProperty.compareTo("theColor") == 0) //Change was in theColor property event = new PropertyChangeEvent( this,changedProperty,null,myColor); else//Change was in the theDate property event = new PropertyChangeEvent( this,changedProperty,null,myDate); //Make a working copy of the list that cannot be // modified while objects on the list are being // notified of the change. Vector tempList; synchronized(this){ tempList = (Vector)propChangeListeners.clone(); }//end synchronized block //Notify all listener objects on the list. Note the // requirement to cast the objects in the list from // Object to PropertyChangeListener. for(int cnt = 0; cnt < tempList.size();cnt++){ PropertyChangeListener theListener = (PropertyChangeListener)tempList.elementAt(cnt); //Invoke the propertyChange() method on theListener theListener.propertyChange(event); }//end for loop }//end notifyPropertyChange }//end class Beans04.java //=======================================================// |
/*File Beans04Test.java Copyright 1997, R.G.Baldwin This program was designed to be compiled and executed under JDK 1.1.3 or later. The purpose of this program is to provide the ability to test the bean class named Beans04.class in a Frame. A Beans04 object is placed in the frame along with five buttons. The visual manifestation of the Bean object is a colored square. Two of the buttons exercise the "get" and "set" methods used to get and set the color value stored in the property named theColor. One button exercises the "set" method used to set the date and time in a write-only property named theDate. Two of the buttons invoke the makeRed() and makeBlue() methods of the Bean which modify the value of the property named theColor. Two listener objects are instantiated and registered to be notified by the bean whenever there is a change in the value of either of the properties. For those cases where information is returned from the Bean, it is displayed on the standard output device. The program was tested using JDK 1.1.3 under Win95. Clicking the button labeled "Set theColor property" produced the following output on the screen. As you can see, the two different listener objects were notified of the same change in the property named theColor. In this case, the value of theColor property was changed to green. FirstListener notified of change Property change source: Beans04[canvas0,31,33,50x50] Property name: theColor New property value: java.awt.Color[r=0,g=255,b=0] Old property value: null SecondListener notified of change Property change source: Beans04[canvas0,31,33,50x50] Property name: theColor New property value: java.awt.Color[r=0,g=255,b=0] Old property value: null As discussed below regarding the makeRed() method, clicking the button labeled "Set theColor property" several times in succession produces only the single output shown above. Clicking the button labeled "Get theColor property" produced the following output on the screen. Since this action didn't cause the property values to change, the listener objects were not notified of the action. java.awt.Color[r=0,g=255,b=0] Clicking the button labeled "Invoke the makeRed Method" produced the following output on the screen. Again both listener objects were notified of the change in the property named theColor with the new value being red. FirstListener notified of change Property change source: Beans04[canvas0,31,33,50x50] Property name: theColor New property value: java.awt.Color[r=255,g=0,b=0] Old property value: null SecondListener notified of change Property change source: Beans04[canvas0,31,33,50x50] Property name: theColor New property value: java.awt.Color[r=255,g=0,b=0] Old property value: null Clicking the button labeled "Invoke the makeRed Method" several times in succession produces only the single output shown above. The Beans04 class only broadcasts an event when the value of the property changes to a new value, and "changing" the property to the same value as before does not cause it to broadcast an event. Clicking the button labeled "Invoke the makeBlue Method" produced the following output on the screen similar to that produced by invoking the makeRed() method described above. FirstListener notified of change Property change source: Beans04[canvas0,31,33,50x50] Property name: theColor New property value: java.awt.Color[r=0,g=0,b=255] Old property value: null SecondListener notified of change Property change source: Beans04[canvas0,31,33,50x50] Property name: theColor New property value: java.awt.Color[r=0,g=0,b=255] Old property value: null As discussed above with regard to the makeRed method, clicking the "Invoke the makeBlue Method" several times in succession produces only the single output shown above. Finally, clicking the button labeled "Set theDate property" produced the following output on the screen. In this case, both listener objects were notified and the information encapsulated in the event object identified the changed property as the property named theDate with a new value as shown. FirstListener notified of change Property change source: Beans04[canvas0,31,33,50x50] Property name: theDate New property value: Sat Oct 18 10:24:49 CDT 1997 Old property value: null SecondListener notified of change Property change source: Beans04[canvas0,31,33,50x50] Property name: theDate New property value: Sat Oct 18 10:24:49 CDT 1997 Old property value: null Unlike the previous discussions involving the theColor property, each time you click the "Set theDate property" button, a new output will be produced. This is because the date information being stored in the theDate property also includes the time and the time always changes between successive clicks on the button. */ import java.awt.*; import java.awt.event.*; import java.beans.*; import java.util.*; //=======================================================// public class Beans04Test extends Frame{ public static void main(String[] args){ new Beans04Test(); }//end main //-----------------------------------------------------// public Beans04Test(){//constructor setTitle("Copyright 1997, R.G.Baldwin"); setLayout(new FlowLayout()); //instantiate a Bean object Beans04 myBean = new Beans04(); add(myBean);//Add it to the Frame //Instantiate several test buttons Button buttonToSetTheColor = new Button("Set theColor property"); Button buttonToGetTheColor = new Button("Get theColor property"); Button buttonToInvokeRedMethod = new Button("Invoke makeRed Method"); Button buttonToInvokeBlueMethod = new Button("Invoke makeBlue Method"); Button buttonToSetTheDate = new Button("Set theDate property"); //Add the test buttons to the frame add(buttonToSetTheColor); add(buttonToGetTheColor); add(buttonToInvokeRedMethod); add(buttonToInvokeBlueMethod); add(buttonToSetTheDate); //Size the frame and make it visible setSize(250,350); setVisible(true); //Register action listener objects for all the test // buttons buttonToSetTheColor.addActionListener( new SetTheColorListener(myBean)); buttonToGetTheColor.addActionListener( new GetTheColorListener(myBean)); buttonToInvokeRedMethod.addActionListener( new RedActionListener(myBean)); buttonToInvokeBlueMethod.addActionListener( new BlueActionListener(myBean)); buttonToSetTheDate.addActionListener( new DateActionListener(myBean)); //Instantiate and register two PropertyChangeListener // objects to listen for changes in the bean's // properties. MyPropertyChangeListener firstListener = new MyPropertyChangeListener(); //Store an identifying name in the listener object firstListener.setTheID("FirstListener"); myBean.addPropertyChangeListener(firstListener); MyPropertyChangeListener secondListener = new MyPropertyChangeListener(); //Store an identifying name in the listener object secondListener.setTheID("SecondListener"); myBean.addPropertyChangeListener(secondListener); //The following statements can be activated to confirm // proper operation of the removePropertyChangeListener // interface of the bean object. When one or the other // of these statements is activated, and the program is // recompiled, only the other listener object is // notified of changes in the values of properties // in the bean. // myBean.removePropertyChangeListener(firstListener); // myBean.removePropertyChangeListener(secondListener); //terminate when Frame is closed this.addWindowListener(new Terminate()); }//end constructor }//end class Beans04Test //=======================================================// //The following class is used to instantiate objects to // be registered to listen to one of the buttons on the // test panel. When the setTheDate button is pressed, the // theDate property is set to the current date and time. class DateActionListener implements ActionListener{ Beans04 myBean;//save a reference to the bean here DateActionListener(Beans04 inBean){//constructor myBean = inBean;//save a reference to the bean }//end constructor public void actionPerformed(ActionEvent e){ //Store the current date and time in the bean property // named theDate. myBean.setTheDate(new Date()); }//end actionPerformed() }//end class DateActionListener //=======================================================// //The following two classes are used to instantiate objects // to be registered to listen to two of the buttons on the // test panel. // When the setTheColor button is pressed, the theColor // property is set to green. // When the getTheColor button is pressed, the current // color is displayed on the standard output device. class SetTheColorListener implements ActionListener{ Beans04 myBean;//save a reference to the bean here SetTheColorListener(Beans04 inBean){//constructor myBean = inBean;//save a reference to the bean }//end constructor public void actionPerformed(ActionEvent e){ myBean.setTheColor(Color.green); }//end actionPerformed() }//end class SetTheColorListener //-------------------------------------------------------// class GetTheColorListener implements ActionListener{ Beans04 myBean;//save a reference to the bean here GetTheColorListener(Beans04 inBean){//constructor myBean = inBean;//save reference to the bean }//end constructor public void actionPerformed(ActionEvent e){ //Display value of the theColor property on the // standard output device. System.out.println(myBean.getTheColor().toString()); }//end actionPerformed() }//end class GetTheColorListener //=======================================================// //The following two classes are used to instantiate objects // to be registered to listen to two of the buttons on the // test panel. When the corresponding the buttons are // pressed, these objects invoke methods of the bean under // test. The first class invokes the makeRed() method and // the second class invokes the makeBlue() method. class RedActionListener implements ActionListener{ Beans04 myBean;//save a reference to the bean here RedActionListener(Beans04 inBean){//constructor myBean = inBean;//save the reference to the bean }//end constructor public void actionPerformed(ActionEvent e){ myBean.makeRed(); }//end actionPerformed() }//end class RedActionListener //-------------------------------------------------------// class BlueActionListener implements ActionListener{ Beans04 myBean;//save a reference to the bean here BlueActionListener(Beans04 inBean){//constructor myBean = inBean;//save the reference to the bean }//end constructor public void actionPerformed(ActionEvent e){ myBean.makeBlue(); }//end actionPerformed() }//end class BlueActionListener //=======================================================// //The following class is used to instantiate objects that // will be bound to the bean in such a way as to be // notified of changes in the property values in the bean // object. When notified of such changes, code in the // propertyChange() method of this class extracts and // displays information about the bean and the properties. class MyPropertyChangeListener implements PropertyChangeListener{ String theID; //store listener object ID here void setTheID(String nameIn){ //method to save the ID of the object theID = nameIn; }//end setTheID() public void propertyChange(PropertyChangeEvent event){ //Extract and display information about the event System.out.println(theID + " notified of change"); System.out.println("Property change source: " + event.getSource()); System.out.println("Property name: " + event.getPropertyName()); System.out.println("New property value: " + event.getNewValue()); System.out.println("Old property value: " + event.getOldValue()); System.out.println();//blank line }//end propertyChange() }//end MyPropertyChangeListener class //=======================================================// class Terminate extends WindowAdapter{ public void windowClosing(WindowEvent e){ //terminate the program when the window is closed System.exit(0); }//end windowClosing }//end class Terminate //=======================================================// |
-end-