COMP434B Software Design JavaBeans: Events and Reflection Events are the primary mechanism by which Java components interact with each other One Bean generates an event and one or more other Beans receive it Java 1.0 event model was based on the component containment hierarchy If a component didn t handle a particular event then it propagated up to the containing component Simple - OK for writing basic applets Doesn t scale well to complicated interfaces 2 Java 1.1 delegation event model Provides a standard mechanism for a source to generate an event and send it to a set of listeners Event An object that describes some state change in a source Can be generated when a user interacts with an element in a GUI Eg pressing a button, moving a slider, dragging the mouse etc Events may also be generated that are not directly caused by user input Eg arrival of incoming data, expiration of a software timer, overflow of a buffer 3 Java 1.1 delegation event model A source - generate events Sources have three main responsibilities: Provide methods that allow listeners to register and deregister for notifications about a specific type of event Generate events Send events to all registered listeners Multiple listeners - multicasting Single listener - unicasting 4 Java 1.1 delegation event model Registering and deregistering methods: public void addtypelistener(typelistener el) public void addtypelistener(typelistener el) throws TooManyListenersException Public void removetypelistener(typelistener el) Type is the type of the event, and el is the event listener Eg. javax.swing.abstractbutton Provides common behaviours for buttons and menu items (subclasses: JButton, JMenuItem, JToggleButton) Generates an action event when pressed/selected public void addactionlistener(actionlistener al) public void removeactionlistener(actionlistener al) 5 Java 1.1 delegation event model A listener - receives event notifications Listeners have three main responsibilities Register to receive notifications about specific events Call appropriate registration method of the source Implement an interface to receive events of that type Deregister if it no longer wants to receive notifications about a specific type of event Call appropriate deregistration method of the source 6 1
Eg. ActionListener interface provides one method to receive action events void actionperformed(actionevent ae) ae is the ActionEvent object generated by the source When a button is pressed, the actionperformed method of all registered listeners is invoked and the event is passed as an argument to that method Event classes A set of classes is provided to represent the various types of UI events (AWT events) Object EventObject AWTEvent ActionEvent AdjustmentEvent ComponentEvent ItemEvent TextEvent ContainerEvent FocusEvent InputEvent PaintEvent WindowEvent 7 KeyEvent 8MouseEvent Event classes EventObject class extends Object Is part of the java.util package Is the superclass of all event state objects Constructor : EventObject(Object source) Source is the object that generates the event Has two methods : Object getsource() - return the generating object String tostring() - return a String equivalent of the event Event classes AWTEvent class extends EventObject Is part of the java.awt package All AWT event types are subclasses of AWTEvent One of its constructors: AWTEvent(Object source, int id) Source is the object generating the event, id identifies the type of event Two frequently used methods: int getid() String tostring() 9 10 AWT Events Examples Listener interfaces EventListener interface is part of the java.util package It does not define any constants or methods, but exists only to identify those interfaces that process events All event listener interfaces must extend this interface Events typically have a corresponding listener interface BlahEvent - BlahListener 11 Action and Item Events Usually generated when buttons are pressed and menu items are selected respectively package actionevents; import javax.swing.jbutton; public class ActionSource1 extends JButton { public ActionSource1() { super("actionsource1"); 2
package actionevents; import javax.swing.jcombobox; public class ActionSource2 extends JComboBox { public ActionSource2() { additem("item 1"); additem("item 2"); additem("item 3"); package actionevents; import javax.swing.jtextarea; public class ActionReceiver extends JPanel implements ActionListener, ItemListener { private JTextArea ta; public ActionReceiver() { ta = new JTextArea(10,20); add(ta); public void actionperformed(actionevent ae) { String ac = ae.getactioncommand(); int modifiers = ae.getmodifiers(); String s = ac; if((modifiers & ActionEvent.ALT_MASK)!= 0) { s += ", ALT_MASK"; if((modifiers & ActionEvent.CTRL_MASK)!= 0) { s += ", CTRL_MASK"; if((modifiers & ActionEvent.META_MASK)!= 0) { s += ", META_MASK"; if((modifiers & ActionEvent.SHIFT_MASK)!= 0) { s += ", SHIFT_MASK"; ta.append(s + "\n"); public void itemstatechanged(itemevent e) { String item = (String)e.getItem(); String info = (e.getstatechange() == ItemEvent.SELECTED)? " (selected)" : " (deselected)"; ta.append(item+info+"\n"); public class ActionEventsDemo { public static void main(string [] args) { ActionSource1 as1 = new ActionSource1(); ActionSource2 as2 = new ActionSource2(); ActionReceiver ar = new ActionReceiver(); if (mode == 1) { as1.setbounds(10,10,150,30); jf.getcontentpane().add(as1); as1.addactionlistener(ar); else { as2.setbounds(10,10,150,30); jf.getcontentpane().add(as2); as2.addactionlistener(ar); as2.additemlistener(ar); AWT Events Examples Mouse Events Are generated when the mouse is clicked, dragged, moved, pressed or released (also when mouse pointer enters or exits a component) MouseEvent class defines many int constants MOUSE_CLICKED, MOUSE_DRAGGED, MOUSE_ENTERED, MOUSE_EXITED etc Some commonly used methods of MouseEvent: Point getpoint() - returns a Point object encapsulating the position of the mouse getx(), gety() - return the x and y coordinates of the mouse Two listener interfaces - MouseListener and MouseMotionListener 18 3
package mouseevents; public class MouseSource extends JPanel { public MouseSource() { Dimension d = new Dimension(100,100); setminimumsize(d); setpreferredsize(d); setmaximumsize(d); public void paintcomponent(graphics g) { super.paintcomponent(g); Dimension d = getsize(); g.drawrect(0, 0, d.width 1, d.height 1); package mouseevents; import javax.swing.jtextarea; import javax.swing.jscrollpane; public class MouseReceiver extends JPanel implements MouseListener, MouseMotionListener { private JTextArea ta; public MouseReceiver() { ta = new JTextArea(15, 40); JScrollPane js = new JScrollPane(ta); add(js); public void mouseclicked(mouseevent me) { ta.append("mouse clicked\n"); public void mouseentered(mouseevent me) { ta.append("mouse entered\n"); public void mouseexited(mouseevent me) { ta.append("mouse exited\n"); public void mousepressed(mouseevent me) { ta.append("mouse pressed\n"); public void mousereleased(mouseevent me) { ta.append("mouse released\n"); public void mousedragged(mouseevent me) { ta.append("mouse dragged\n"); Adapter Classes An adapter class provides empty implementations of all methods defined in a specific event listener interface Useful if you only want to process a subset of the events that are received by a particular interface MouseListener has five methods. If for example you only wanted to process mouseclicked() then your class could extend MouseAdapter and overide only the mouseclicked method Can t be used in this way if your class already extends some other class public void mousemoved(mouseevent me) { ta.append("mouse moved\n"); 22 Anonymous Inner Classes An inner class is one that is defined within the scope of another class Has access to all the variables and methods of the enclosing class An anonymous inner class is one that does not have a name Use when you only ever need one object of the class Can be extremely useful when writing code to process events 23 package dot; public class Dot extends JPanel { private Point p; public Dot() { Dimension d = new Dimension(200, 200); setminimumsize(d); setpreferredsize(d); setmaximumsize(d); p = new Point(100, 100); addmouselistener(new MouseAdapter() { public void mouseclicked(mouseevent me) { changepoint(me.getpoint()); ); 4
public void changepoint(point newp) { p = newp; repaint(); public void paintcomponent(graphics g) { super.paintcomponent(g); Dimension d = getsize(); g.drawrect(0, 0, d.width 1, d.height 1); g.fillrect(p.x 2, p.y 2, 4, 4); Dynamic Event Handlers java.beans.eventhandler (introduced in Java 1.3) Provides support for dynamically generating event listeners Can handle simple situation where event listener methods execute a single statement involving an incoming event and a target object Only provides a subset of what can be done with inner classes However, memory and disk footprint is smaller than for inner classes Using EventHandler requires one class per listener type, using anonymous inner classes requires one class per 26 listener object java.beans.eventhandler Has various static factory methods for creating proxy objects that implement a given listener interface EventHandler objects are used behind the scenes to encapsulate info about the event, the target object, the method to call on the target and any argument to the method java.lang.reflect.proxy class implements listener methods; calls to listener methods are encoded and passed on to the EventHandler s invoke method 27 package dotv2; import java.beans.eventhandler; public class Dot extends JPanel { private Point p; public Dot() { Dimension d = new Dimension(200, 200); Object handler = EventHandler.create(MouseListener.class, this, "changepoint", "point", "mouseclicked"); addmouselistener((mouselistener)handler); java.beans.eventhandler Intended to be used by builder tools we will see how later Removes the need for Beans to implement specific listener interfaces Allows builder tools to connect arbitrary beans together Weaker typing specific listener interfaces implemented by a bean can be bypassed Limited to transferring a single property from source event or bean to target bean 29 package actioneventsv2; public class ActionSource2 extends JComboBox { public String getcurrentselecteditemtext() { return getselecteditem().tostring(); public ActionSource2() { additem("item 1"); additem("item 2"); additem("item 3"); public class ActionReceiver extends JPanel { private JTextArea ta; public ActionReceiver() { ta = new JTextArea(10,20); add(ta); public void accepttext(string text) { ta.append(text + "\n"); 5
package mouseeventsv2; public class MouseReceiver extends JPanel { private JTextArea ta; public MouseReceiver() { ta = new JTextArea(15, 40); JScrollPane js = new JScrollPane(ta); add(js); public void mouseclicked() { ta.append("mouse clicked\n"); public void mouseentered() { ta.append("mouse entered\n"); Custom Events Custom events are useful when one of your objects wants to notify another object about a change in its state Six steps involved: You must define a new class to describe the event (must extend EventObject) You must define a new interface for listeners to receive this type of event (must extend EventListener) The source must provide methods to allow listeners to register and deregister for event notifications The source must provide code to generate the event and send it to all registered listeners The listener must implement the interface to receive the event The listener must register/deregister to receive the notifications public void mouseexited() { ta.append("mouse exited\n"); 32 Colour Event Example package cselector; import java.util.*; public class ColorEvent extends EventObject { private Color color; public ColorEvent(Object source, Color color) { super(source); this.color = color; public Color getcolor() { return color; package cselector; import java.util.*; public interface ColorListener extends EventListener { public void changecolor(colorevent ce); package cselector; public class Painter extends JPanel implements ColorListener { private Color color; // constructor + paintcomponent method omitted see source public void setcolor(color c) { color = c; repaint(); public void changecolor(colorevent ce) { color = ce.getcolor(); repaint(); package cselector; import java.beans.*; import java.util.*; import javax.swing.jscrollbar; import javax.swing.jlabel; public class Selector extends JPanel implements AdjustmentListener { private Color color; private Vector listeners; private JScrollBar rscrollbar, gscrollbar, bscrollbar; // constructor, paintcomponent & scrollbar handling code // omitted see source for details public Color getcolor() { return color; public void firecolorevent(colorevent ce) { Vector v; synchronized(this) { v = (Vector)listeners.clone(); for(int i = 0; i < v.size(); i++) { ColorListener cl = (ColorListener)v.elementAt(i); cl.changecolor(ce); public void addcolorlistener(colorlistener cl) { listeners.addelement(cl); public void removecolorlistener(colorlistener cl) { listeners.removeelement(cl); 6
Reflection and Introspection Reflection is the ability to obtain information about the fields, constructors and methods of a class at runtime The typical Bean developer does not write code that uses reflection directly However, it is useful to have some understanding of reflection because Introspection is based on it Class Reflection The Java Virtual Machine creates an instance of the class java.lang.class for each type, including classes, interfaces, arrays, and simple types Class provides various instance methods that allow you to get information about that type Provides more than 30 different instance methods! See the javadocs 37 38 package reflect; public class IsInterfaceDemo { public static void main(string args[]) { try { Reflection // Get the class object Class c = Class.forName(args[0]); The java.lang.reflect package contains interfaces and classes that encapsulate information about constructors, methods, fields etc. Eg. java.lang.reflect.field contains methods that allow you to read and write the value of a field within another object (subject to Java language access control) // Determine if it represents a class or interface if(c.isinterface()) { System.out.println(args[0] + " is an interface"); else { System.out.println(args[0] + " is not an interface"); catch(exception ex) { // the printstacktrace method is extremely useful for // debugging :-) ex.printstacktrace(); 40 package reflect; import java.lang.reflect.*; public class GetFieldsDemo { public static void main(string args[]) { try { // Get the class object Class c = Class.forName(args[0]); // Display the fields Field fields[] = c.getfields(); for(int i = 0; i < fields.length; i++) { System.out.println(fields[i].getName()); catch(exception ex) { ex.printstacktrace(); Reflection The class Method in java.lang.reflect alows you to get information about a method Some methods in Method: Class [] getexceptiontypes() Class [] getparametertypes() Class getreturntype() Object invoke(object obj, Object [] args) Allows a builder tool to dynamically invoke a method of a Bean! This is exactly what is needed to customize a Bean by accessing its properties and to connect several Beans 42 7
package reflect; import java.lang.reflect.*; // invoke a method in a class, where the class name, // method name, and any args are supplied on the // command line public class InvokeDemo { public static void main(string args[]) { try { // Get the class object Class c = Class.forName(args[0]); // Get reference to Method object int nparameters = args.length 2; Class parametertypes[] = new Class[nparameters]; for(int i = 0; i < nparameters; i++) { parametertypes[i] = double.class; Method m = c.getmethod(args[1], parametertypes); // Generate parameters array Object parameters[] = new Double[nparameters]; for(int i = 0; i < nparameters; i++) { parameters[i] = new Double(args[i + 2]); // Invoke method Object r; if(modifier.isstatic(m.getmodifiers())) { r = m.invoke(null, parameters); else { r = m.invoke(c.newinstance(), parameters); // Display results if (r!= null) { System.out.println(r); catch(exception ex) { ex.printstacktrace(); 8