JavaBeans - Event Handling and Properties
Download
Report
Transcript JavaBeans - Event Handling and Properties
JavaBeans Event Handling
and Properties
Event Handling and
Properties
Handling Bean Events
Event Objects, Listeners, and Sources
Event Adapters
Property Management
Indexed, Bound and Constrained Properties
Introspection - Design Patterns
Explicitly Defining Bean Information
Java Event Model
Events Are Objects In Java
JavaBeans Model based on Event Handling
introduced in Java 1.1 API
Event Objects Are Generated By Components
for Communication between Beans
Events Propagate from Source to Target
Listener Objects
java.util package provides base classes
Event Objects
Base class: java.util.EventObject
public EventObject(Object source)
Encapsulates information about event
References Source of Event
Create Event-Specific Subclasses of
EventObject
EventObject Example
public class VoltsChangedEvent extends java.util.EventObject
{
protected double theVolts;
public VoltsChangedEvent(Object source, double volts)
{
super(source);
theVolts = volts;
}
public double getVolts()
{
return theVolts;
}
}
AWTEvent Classes
KeyEvent
MouseEvent
ContainerEvent
ComponentEvent
ActionEvent
ItemEvent
WindowEvent
AdjustmentEvent
PropertyChangeEvent
java.beans package
Sent when bound or constrained properties are
altered
JavaBeans must generate and send
PropertyChangeEvent objects
Listener Objects
Listeners receive events from source objects
Methods are invoked on the listener and event
object is passed as a parameter
To receive event notification, a class
implements a listener interface
Listener Interface Base class:
java.util.EventListener
An event fired by a source object will cause the
associated method of the listener object to be
called
EventListener Example
public interface VoltsChangeListener
extends java.util.EventListener
{
void voltsChanged(VoltsChangedEvent e);
}
Some AWT Listener
Interfaces & Methods
ActionListener
public void actionPerformed(ActionEvent e);
ItemListener
public void itemStateChanged(ItemEvent e);
MouseListener
public void mouseClicked(MouseEvent e);
public void mouseEntered(MouseEvent e);
public void mouseExited(MouseEvent e);
public void mousePressed(MouseEvent e);
public void mouseReleased(MouseEvent e);
Java Beans Listeners
java.beans.PropertyChangeListener
Bound Properties
public void propertyChange(PropertyChangeEvent e);
java.beans.VetoableChangeListener
Constrained Properties
public void vetoableChange(PropertyChangeEvent e) throws
PropertyVetoException;
Event Sources
Objects that fire events
Register and Unregister Listeners
Registration Design Patterns
public void addEventNameListener (EventNameListener l);
public void removeEventNameListener (EventNameListener l);
public EventNameListener[] getEventNameListeners ();
Unicast and Multicast Event
Delivery
Multicast - Multiple Listeners Registered with
Single Event Source
Unicast - Only one Listener Registered with
Single Event Source
Unicast Registration Design Patterns
public void addEventNameListener (EventNameListener l)
throws java.util.TooManyListenersException;
public void removeEventNameListener (EventNameListener l);
public EventNameListener getEventNameListener ();
Event Source Example
import java.util.Vector;
public class Battery
{
protected double currentVolts = 12.0;
private Vector voltsChangeListeners = new Vector();
public Battery(double initVoltage)
{ currentvolts = initVoltage; }
public Battery() {}
Event Source Example Continued
public synchronized void
addVoltsChangeListener(VoltsChangeListener l)
{
if (!voltsChangeListeners.contains(l))
voltsChangeListeners.addElement(l);
}
public synchronized void
removeVoltsChangeListener(VoltsChangeListener l)
{
if (voltsChangeListeners.contains(l))
voltsChangeListeners.removeElement(l);
}
Event Source Example Continued
public synchronized VoltsChangeListener[]
getVoltsChangeListeners()
{
return (VoltsChangeListener [])
voltsChangeListeners.toArray(
new VoltsChangeListener[
voltsChangeListeners.size()]);
}
Event Source Example Continued
protected void notifyVoltsChange()
{
VoltsChangedEvent e =
new VoltsChangedEvent(this, currentVolts);
Vector v;
synchronized(this) {
v = (Vector) voltsChangeListeners.clone();}
int cnt = v.size();
for(int i = 0; i < cnt; i++)
{
VoltsChangeListener list =
(VoltsChangeListener)v.elementAt(i);
list.voltsChanged(e);
}
}
} // delimits Class definition
Registering an AWT
Listener Object
Use the add<event>Listener() method to
register a qualified listener with a specific
source object
Appropriate add<event>Listener() methods are
available to source components which trigger
the specific events
This example shows that the argument of the
method is the listener object
button.addActionListener(this);
The Recharger Class
public class Recharger implements VoltsChangeListener
{
protected Battery theBattery;
public Recharger(Battery b)
{
theBattery = b;
theBattery.addVoltsChangeListener(this);
}
public void voltsChanged(VoltsChangedEvent e)
{
// turn the charging switch on or off
}
}
Event Adapters
Listener code could get unmanageable
Listener may want to receive several different
event source objects
Listener may want to listen to several objects
generating the same event
Handling Events with
Adapters
Event Source
Register
Listener
Fire Event
Event
Object
Event Adapter
Forward
Event
Event
Object
Create
Adapter
Event Listener
Single Instance Generic
Adapter
Handler1()
Event Listener
Handler2()
Handler3()
Forward
Events
Adapter
Fire
Events
Event Source
1
Event Source
2
Event Source
3
Implementing a Dispatch
Table using Java Reflection
Target makes an instance of the Adapter
Adapter discovers the target class at runtime
Adapter discovers the target methods at
runtime
Adapter can invoke the target method
Finding the Class
Battery b = new Battery(12.5);
Recharger rech = new Recharger(b);
try {
Class theClass = rech.getClass();
}
catch(java.lang.ClassNotFoundException e) {}
ALSO:
Class theClass = Recharger.class;
Finding the Method
Assume a setName method for the Recharger
class with the following signature:
void setName(String s);
Battery b = new Battery(12.5);
Recharger rech = new Recharger(b);
try {
Class theClass = rech.getClass();
Class paramClasses[] = { java.lang.String.class };
java.lang.reflect.Method m =
theClass.getMethod(“setName”,paramClasses);
Object param[] = { new String(“Recharger One”) };
m.invoke(rech, param);
}
catch(Exception e) {}
Generic Voltage Adapter
Handles multiple Battery objects as event
sources
Maps to arbitrary target object, an instance of
Recharger
Dispatch methods all have the same signature:
public void <methodName> (VoltsChangedEvent e);
Voltage Adapter Example
import java.lang.reflect.*;
import java.util.*;
public class GenericVoltageAdapter
implements VoltsChangeListener
{
protected Object theTarget;
protected Class theTargetClass;
protected final static Class paramClass[] =
{ VoltsChangedEvent.class };
protected Hashtable map = new Hashtable();
public GenericVoltageAdapter(Object target)
{
theTarget = target;
theTargetClass = target.getClass(); }
Voltage Adapter Example Continued
public void registerEventHandler
(Battery bat, String methodName) throws NoSuchMethodException
{
Method m = theTargetClass.getMethod(methodName, paramClass);
bat.addVoltsChangeListener(this);
map.put(bat, m);
}
public void voltsChanged(VoltsChangedEvent e) {
try {
Method m = (Method)map.get(e.getSource());
Object params[] = { e };
m.invoke(theTarget, params);
}
catch (Exception e) {System.out.println(e);} }
Revised Recharger Class
public class Recharger
{
protected Battery battOne;
protected Battery battTwo;
protected GenericVoltageAdapter voltAdapter;
public Recharger(Battery b1, Battery b2)
{
battOne = b1; battTwo = b2;
voltAdapter = new GenericVoltageAdapter(this);
voltAdapter.registerEventHandler(battOne, “volts1”);
voltAdapter.registerEventHandler(battTwo, “volts2”);
}
// do something specific to battery1 changes
public void volts1(VoltsChangedEvent e) { }
// do something specific to battery2 changes
public void volts2(VoltsChangedEvent e) { }
}
Properties in JavaBeans
Data Portion of Bean
Define Behavior and State
Exposed to Visual Programming Tools for
Customization
Can Be Any Data Type
NOT a one-to-one correspondence between
Properties and data members of a class
Accessor Methods
Getter and Setter Methods
Only Getter -> Read-only property
Only Setter -> Write-only property
Design Patterns:
public void set<PropertyName> (<PropertyType> x);
public <PropertyType> get<PropertyName>();
Boolean Property Design Pattern for Getter:
public boolean is<PropertyName>();
Accessor Methods Example
import java.util.Vector;
public class Battery
{
protected double currentVolts = 12.0;
private Vector voltsChangeListeners = new Vector();
// Constructors Here
public double getCurrentVoltage() {
return currentVolts; }
public void setCurrentVoltage(double v) {
currentVolts = v;
// other processing
}
Indexed Properties
Ordered collection of values associated with one
name
Implemented as an array
Design Patterns for accessing all elements:
public void set<PropertyName> (<PropertyType>[] x);
public <PropertyType>[] get<PropertyName>();
Design Patterns for accessing single element:
public void set<PropertyName> (int index, <PropertyType> x);
public <PropertyType> get<PropertyName>(int index);
Indexed Properties Example
public class Recharger
{
protected Battery[] battArray;
public void setBatteries(Battery[] b) {
battArray = b; }
public Battery[] getBatteries() {
return battArray; }
public void setBatteries(int index, Battery b) {
battArray[index] = b; }
public Battery getBatteries(int index) {
return battArray[index]; }
}
Bound Properties
Support change notifications
Non-specific property binding
PropertyChangeEvent
PropertyChangeListener
Design Patterns for registering and unregistering
listeners for Bound Properties
public void addPropertyChangeListener(PropertyChangeListener l);
public void removePropertyChangeListener(PropertyChangeListener l);
PropertyChangeEvent
Constructor
PropertyChangeEvent(Object source, String
propName, Object oldValue, Object newValue);
Methods
public Object getNewValue();
public Object getOldValue();
public Object getPropagationId();
public String getPropertyName();
public void setPropagationId(Object propID);
PropertyChangeListener
public interface PropertyChangeListener
extends EventListener {
public void propertyChange(PropertyChangeEvent e);
}
Bound Property Example
import java.util.Vector;
import java.beans.*;
public class Battery
{
protected double currentVolts = 12.0;
protected Vector propChangeListeners = new Vector();
public Battery(double initVoltage)
{ currentvolts = initVoltage; }
public Battery() {}
Bound Property Example Continued
public synchronized void
addPropertyChangeListener(PropertyChangeListener l)
{
if (!propChangeListeners.contains(l))
propChangeListeners.addElement(l);
}
public synchronized void
removePropertyChangeListener(PropertyChangeListener l)
{
if (propChangeListeners.contains(l))
propChangeListeners.removeElement(l);
}
Bound Property Example Continued
protected void notifyVoltsChange()
{
PropertyChangedEvent e =
new PropertyChangedEvent(this, “CurrentVoltage”,
null, new Double(currentVolts));
Vector v;
synchronized(this) {
v = (Vector) propChangeListeners.clone();}
int cnt = v.size();
for(int i = 0; i < cnt; i++)
{
PropertyChangeListener list =
(PropertyChangeListener)v.elementAt(i);
list.propertyChange(e);
}}
} // delimits Class definition
Revised Recharger Class
public class Recharger implements PropertyChangeListener
{
protected Battery theBattery;
public Recharger(Battery b)
{
theBattery = b;
theBattery.addPropertyChangeListener(this);
}
public void propertyChange(PropertyChangeEvent e)
{
if(e.getSource() == theBattery &&
e.getPropertyName() == “CurrentVoltage”)
{ Battery b = (Battery)e.getSource();
Object o = e.getNewValue();
double newVoltage;
if ( o == null ) newVoltage = b.getCurrentVoltage();
else newVoltage = ((Double)o).doubleValue(); }
}}
PropertyChangeSupport
import java.util.Vector;
import java.beans.*;
public class Battery extends PropertyChangeSupport
{
protected double currentVolts = 12.0;
public Battery(double initVoltage){
this();
currentvolts = initVoltage; }
public Battery() { super(this);}
public double getCurrentVoltage() {
return currentVolts; }
protected void notifyVoltsChange() {
firePropertyChange(“CurrentVoltage”, null,
new Double(currentVolts)); }
}
Constrained Properties
Enable Outside Party Validation
VetoableChangeListener
Design Patterns for registering and unregistering
listeners for Constrained Properties
public void addVetoableChangeListener(VetoableChangeListener l);
public void removeVetoableChangeListener(VetoableChangeListener l);
PropertyVetoException
Design Patterns for setting and getting Constrained
Properties
public <PropertyType> get<PropertyName>();
public void set<PropertyName>(<PropertyType> v) throws
PropertyVetoException
Using Bound &
Constrained Properties
When Change is Vetoed, New Event must be
fired
Listeners cannot assume universal acceptance
of constrained property
Properties can be both Bound and Constrained
Fire VetoableChangeEvent
Change Property Value if no veto
Fire PropertyChangeEvent
VetoableChangeSupport
Manages Constrained Properties
Manages Firing of Events
Constrained Property
Example
public class Recharger implements PropertyChangeListener
{
protected Battery theBattery;
protected double minVoltage = 12.0;
protected VetoableChangeSupport;
public Recharger(Battery b)
{
theBattery = b;
theBattery.addPropertyChangeListener(this);
vSupport = new VetoableChangeSupport(this);
}
public void addVetoableChangeListener(VetoableChangeListener l)
{vSupport.addVetoableChangeListener(l);}
public void removeVetoableChangeListener(VetoableChangeListener l)
{vSupport.removeVetoableChangeListener(l);}
Constrained Property
Example - Continued
public double getMinimumVoltage()
{
return minVoltage;
}
public void setMinimumVoltage(double v) throws PropertyVetoException
{
if (v < 6.0) throw new PropertyVetoException();
vSupport.fireVetoableChange(“MinimumVoltage”,
new Double(minVoltage), new Double(v));
minVoltage = v;
}
} // delimits class definition
Listeners for Specific
Properties
Design Patterns for registering and
unregistering listeners for specific Bound
Properties
public void add<PropertyName>Listener(PropertyChangeListener l);
public void remove<PropertyName>Listener(PropertyChangeListener l);
Design Patterns for registering and
unregistering listeners for specific
Constrained Properties
public void add<PropertyName>Listener(VetoableChangeListener l);
public void remove<PropertyName>Listener(VetoableChangeListener l);
Introspection
Beans expose information about how they work
Application builder tools analyze these features
Low-Level Services: Reflection Facilities
High-Level Services: Limited to Public
Properties, Methods, and Events
Design Patterns
Design Patterns Review
Property Design Patterns
Simple
public <PropertyType> get<PropertyName>();
public void set<PropertyName>(<PropertyType> x);
Boolean
public boolean is<PropertyName>();
Indexed
public
public
public
public
<PropertyElement> get<PropertyName>(int i);
void set<PropertyName>(int i, <PropertyElement> x);
<PropertyElement> [] get<PropertyName>();
void set<PropertyName>(<PropertyElement>[] x);
Design Patterns Review Continued
Event Design Patterns
Multicast
public void add<EventListenerType>(<EventListenerType> x);
public void remove<EventListenerType>(<EventListenerType> x);
public <EventListenerType>[] get<EventListenerType>s();
Unicast
public void add<EventListenerType>(<EventListenerType> x)
throws TooManyListeners;
Method Design Patterns
None specified
Explicitly Providing Bean
Information
Alternative to Automatic Introspection
Option for controlling Bean Information
Can be used in combination with Automatic
Introspection
BeanInfo interface
The Introspector
java.beans.Introspector class
Obtains Bean Information
Two-tier approach
Looks for explicit information
Uses Reflection Techniques combined with
Design Patterns
The BeanInfo Interface
Implemented by Bean Information Class
Methods gather information about Bean
Design Pattern:
JavaBean class name: Car
Associated BeanInfo class name: CarBeanInfo
Advantage: Bean does not carry extra baggage
Disadvantage: Tight Coupling Relying on
Design Pattern
BeanInfo Interface Methods
public BeanInfo[] getAdditionalBeanInfo(): returns additional
BeanInfo objects relevant to the main Bean
public BeanDescriptor getBeanDescriptor(): returns Bean Descriptor
public int getDefaultEventIndex(): returns default event index
public int getDefaultPropertyIndex(): returns default property index
public EventSetDescriptor[] getEventSetDescriptors(): returns event set
descriptors
public Image getIcon(int iconkind): returns specified icon
public MethodDescriptor[] getMethodDescriptors(): returns method
descriptors
public PropertyDescriptor[] getPropertyDescriptors(): returns property
descriptors
SimpleBeanInfo class
Implements BeanInfo interface
Derive your own BeanInfo class by
extending SimpleBeanInfo
Additional convenience method:
public Image loadImage(String resourceName);
Bean Descriptor
Describes class that implements the
Bean
Constructor:
public BeanDescriptor(Class beanClass);
Some FeatureDescriptor methods:
public void setDisplayName(String dispName);
public String getDisplayName();
Bean Descriptor Example
import java.beans.*;
public class RechargerBeanInfo extends SimpleBeanInfo
{
public BeanDescriptor getBeanDescriptor()
{
BeanDescriptor bd = new BeanDescriptor(Recharger.class);
bd.setDisplayName(“Simulated Recharger”);
return bd;
}
}
Setting Bean Icons
Icons used in Palettes or Tool Bars
Four supported .GIF formats
Icon
16 x 16 color
32 x 32 color
16 x 16 monochrome
32 x 32 monochrome
Constant
ICON_COLOR_16x16
ICON_COLOR_32x32
ICON_MONO_16x16
ICON_MONO_32x32
import java.beans.*;
import java.awt.Image;
Setting Bean Icons Example
public class RechargerBeanInfo extends SimpleBeanInfo
{
public Image getIcon(int iconKind)
{
if(iconKind == BeanInfo.ICON_COLOR_16x16) {
Image img = loadImage(“recharger.gif”);
return img; }
return null;
}
}
Summary
Handling Bean Events
Event Objects, Listeners, and Sources
Event Adapters
Property Management
Indexed, Bound and Constrained Properties
Introspection - Design Patterns
Explicitly Defining Bean Information