Personal notes on Java
For other technologies like HTML, CSS, .NET, PHP, etc. check my other blog

General references:


Java defined Events, Listeners and Adapters

In java a component/object that fires some type of event (ex. ActionEvent) also has a corresponding method to add observers that will listen to this events [ex. addActionListener(ActionListener listener) ] .
This "add Listener" methods receive an implementation of the corresponding interface (ex. ActionListener) that you manually code with the required logic to execute when the event gets fired.

This interfaces may define multiple methods that you must implement but sometimes you are interested in handling only on of them.
For this java library sometimes also has corresponding adapter classes that implement this interfaces with default empty methods, so that you can use them (instead of the interface directly) and implement only the methods you need.
TIP: a good way to see if java already provides an adapter for the type of Listener you need, is to check the Javadoc of that Listener interface.
Ex.: if you need to implement a MouseWheelListener interface:
  1. visit the javadoc page for MouseWheelListener;
  2. search the word "adapter";
  3. under the section "All Known Implementing Classes" you'll find MouseAdapter. This adapter provides an implementation of MouseWheelListener (along with other listeners) with empty methods.

Main packages

Java library defines a lot of Events and their corresponding Listener interfaces and (in some cases) Adapter classes.
Some main packages where they are defined are:

Package java.awt.event

Provides interfaces and classes for dealing with different types of events fired by AWT components.

Package javax.swing.event

Provides for events fired by Swing components.
  • Events:
    CaretEvent; ChangeEvent; HyperlinkEvent; MenuDragMouseEvent; MenuEvent; MenuKeyEvent; PopupMenuEvent; SwingPropertyChangeSupport; UndoableEditEvent
    ; (many other...);
     
  • Listeners:
    «every event has its corresponding Listener interface»;
     
  • Adapters:
    - InternalFrameAdapter (adapter for InternalFrameListener);
    - MouseInputAdapter (adapter for multiple mouse related listeners: MouseListener, MouseMotionListener, MouseWheelListener, EventListener, MouseInputListener);

Package java.beans

Defines some PropertyChange related events and listeners and some other util classes to deal with events on javabeans.
TODO (complete)

Check the description for the PropertyChange API further down this page.

Handle events

Just like int the Observer pattern you can register observers (listeners) that listen to events fired by swing components.
Example of how it works:
  1. Among other events, a javax.swing.JButton fire an java.awt.event.ActionListener
    when you press it.
     
  2. In order to do something when this event is fired, you need to register any interested observers (listeners) with it.
     
  3. The JButton provides specific methods to register (add) observers (listeners) for each event that it fires. For example, for the ActionEvent mentioned above you would use the JButton method:
    public void addActionListener(ActionListener l)
  4. This method receives an java.awt.event.ActionListener (interface) type as argument. This is the interface that your observers (listeners) need to implement in order to handle the event when it gets fired.
     
  5. The ActionListener interface only defines one method that your observers must implement:
    void     actionPerformed(ActionEvent e) 
    This method will be invoked when the event is fired: its the place where you put the logic to do something.
     
  6. You can use multiple approaches to implement the required interface in your observers (listeners).
    For example, for the ActionListener mentioned above you could:
    1. create a anonymous inner class that implements ActionListener and routes the event to a method in your class;
    2. make your class implement ActionListener;
    3. create, for each button, a dedicated inner class that implements ActionListener and will be responsible for handling each button's events;
    4. if you are not interested on implementing all the events of a Listener interface, java already has some built int abstract adapter classes that implement many of this Listener interfaces with empty method implementations that you can use coding only the methods you need.
    Each have its own pros/cons and of course, you can always implement them in many other creative ways.

The Property Change Listener API

References:

Registering a PropertyChangeListener: 

Using for example the usefull java.beans.PropertyChangeSupport object: This is a utility class that can be used by beans that support bound properties. It manages a list of listeners and dispatches PropertyChangeEvents to them. You can use an instance of this class as a member field of your bean and delegate these types of work to it. The PropertyChangeListener can be registered for all properties or for a property specified by name. (The javadoc includes a simple example)
Method Purpose
addPropertyChangeListener(PropertyChangeListener) Add a property-change listener to the listener list.
addPropertyChangeListener(String, PropertyChangeListener) Add a property-change listener for a specific property. The listener is called only when there is a change to the specified property.
Interface java.beans.PropertyChangeListener
Because PropertyChangeListener has only one method, it has no corresponding adapter class.
Method Purpose
propertyChange(PropertyChangeEvent) Called when the listened-to bean changes a bound property.
Class java.beans.PropertyChangeEventA "PropertyChange" event gets delivered whenever a bean changes a "bound" or "constrained" property. A PropertyChangeEvent object is sent as an argument to the PropertyChangeListener and VetoableChangeListener methods.

Method Purpose
Object getNewValue()
Object getOldValue()
Return the new, or old, value of the property, respectively.
String getPropertyName() Return the name of the property that was changed.
void setPropagationId() Get or set the propagation ID value. Reserved for future use.
Example with source code:
A simple MVC app that uses the PropertyChangeListener to implement an Observer Pattern - the views observe (listen) model changes:
Download source code (Netbeans 7 project)

Excerpts from this app:
The model:
  • the model is a simple javabean;
  • the model has an instance of the class java.beans.PropertyChangeSupport to add/remove listners;
  • the set methods fire the property change events;
    NOTE: if the oldValue equals the newValue then the event wont be fired (this logic is transparent to the programmer - download and run the app to test it).

 public class MyModel {
    private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
    private String nome = "";
    private String apelido = "";
   
    ...
   
    public void addPropertyChangeListener(PropertyChangeListener listener) {
        this.pcs.addPropertyChangeListener(listener);        
    }
   
    public void addPropertyChangeListener(String propriedade,PropertyChangeListener listener){
        this.pcs.addPropertyChangeListener(propriedade, listener);
    }

    public void removePropertyChangeListener(PropertyChangeListener listener) {
        this.pcs.removePropertyChangeListener(listener);
    }

    public void setNome(String nome) {        
        String oldValue = this.nome;
        this.nome = nome;
        out("Model: valor de nome foi alterado de "+oldValue+" para "+nome);
        this.pcs.firePropertyChange("nome", oldValue, nome);
    }


The Views:
  • The views implement the Interface PropertyChangeListner (it has only 1 method: "propertyChange")
public class MyViewA implements PropertyChangeListener {     
    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        out("ViewA - recebeu evento de propertyChange");
        if (evt.getPropertyName().equals("nome"))
            out("ViewA - valor da propriedade 'nome' actualizado de '"+evt.getOldValue()+"' para '"+evt.getNewValue()+"'");
        else if(evt.getPropertyName().equals("apelido"))
            out("ViewA - valor da propriedade 'apelido' actualizado de '"+evt.getOldValue()+"' para '"+evt.getNewValue()+"'");
        else
            out("ViewA - Nenhuma property match");
    } 


The controller:
  • the Controller creates the model and the views;
  • the Controller adds the views has listners (observers) of the model (so, the model and view are loosely coupled - they dont know nothing about each other);
  • the Controller makes changes to the model and the model will issue propertyChange events to the views to update them;

public class Controller {

    public static void main(String args[]) {
        out("Controller - creating model with properties: nome=aa apelido=bb");
        MyModel model = new MyModel("aa", "bb");
        
        out("Controller - creating views and registering them has model observers");
        MyViewA view = new MyViewA();        
        model.addPropertyChangeListener(view);  
        out("Controller - ViewA is observing all model properties");
        
        MyViewB view2 = new MyViewB();
        model.addPropertyChangeListener("nome", view2);
        out("Controller - ViewB is observing only the 'nome' property");

        out("\nController - Setting model properties with NEW VALUES: nome=cc apelido=dd");
        model.setNome("cc");
        model.setApelido("dd");  
        
        out("\nController - Setting model properties with SAME VALUES: nome=cc apelido=dd"
                + "\n  NOTE: since its the same values the propertychange event wont be fired and the views dont get updated");
        model.setNome("cc");
        model.setApelido("dd");  
        
        out("\nController - done.");
    } 

Sem comentários:

Enviar um comentário