javabeans event handling and properties. event handling and properties handling bean events event...

61
JavaBeans Event Handling and Properties

Post on 21-Dec-2015

274 views

Category:

Documents


0 download

TRANSCRIPT

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 Examplepublic 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

ActionListenerpublic void actionPerformed(ActionEvent e);

ItemListenerpublic void itemStateChanged(ItemEvent e);

MouseListenerpublic 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 Patternspublic 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 Classpublic 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

Event Adapter

Event Listener

Event Object

Event Object

Fire Event

Forward Event

CreateAdapter

RegisterListener

Single Instance Generic Adapter

Event ListenerHandler1() Handler2() Handler3()

Adapter

Event Source1

Event Source2

Event Source3

ForwardEvents

FireEvents

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

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) {}

Assume a setName method for the Recharger class with the following signature:

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 Exampleimport 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 Classpublic 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 changespublic 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 Examplepublic 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

ConstructorPropertyChangeEvent(Object source, String propName, Object oldValue, Object newValue);

Methodspublic 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 Exampleimport 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 Classpublic 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(); }

}}

PropertyChangeSupportimport 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);

Booleanpublic boolean is<PropertyName>();

Indexedpublic <PropertyElement> get<PropertyName>(int i);public void set<PropertyName>(int i, <PropertyElement> x);public <PropertyElement> [] get<PropertyName>();public 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();

Unicastpublic 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 Descriptorpublic int getDefaultEventIndex(): returns default event indexpublic int getDefaultPropertyIndex(): returns default property indexpublic EventSetDescriptor[] getEventSetDescriptors(): returns event set

descriptorspublic Image getIcon(int iconkind): returns specified iconpublic MethodDescriptor[] getMethodDescriptors(): returns method

descriptorspublic 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 Constant

16 x 16 color ICON_COLOR_16x1632 x 32 color ICON_COLOR_32x3216 x 16 monochrome ICON_MONO_16x1632 x 32 monochrome ICON_MONO_32x32

Setting Bean Icons - Example

import java.beans.*;import java.awt.Image;

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