MokaByte Numero 16 - Febbraio 1998
Nuova gestione di
eventi per delega 
di 
Daniela Ruggeri
Confronto tra la vecchia gestione di eventi 1.0. e quella nuova a delega 1.1

 


Dopo l'ottimo articolo di Massimo Carli sul numero di MokaByte di Febbraio 1997  ho ritenuto necessario scrivere un articolo di completamento che mettesse a confronto le differenze tra le due gestioni di eventi.
L'articolo si rivolge a quanti ancora non hanno familiarità con la nuova gestione degli eventi a delega e sono restii per tale motivo ad abbandonare la vecchia.


Introduzione.
In questo articolo vengono affrontate le differenze tra la vecchia gestione degli eventi riguardante il package AWT 1.0 e la nuova (Delegation Event Model) riguardante il package AWT 1.1.
Nella vecchia gestione esiste solo un evento che viene intercettato ed elaborato da appositi metodi associati all'oggetto coinvolto (target). Questi metodi sono generici (action() e handleEvent()) o specializzati sul particolare evento (es. mouseDown(), keyPress(), ecc.) e si trovano solamente solamente nella classe che li ospita.
Ogni metodo che gestisce l'evento è di tipo booleano e quando restituisce true tutto finisce, quando invece restituisce false e l'evento viene spedito al contenitore dell'oggetto, e questa fase si ripete fino a quando il metodo opportuno restituisce true o fino a quando non esistono più contenitori.
Con la nuova gestione degli eventi in AWT 1.1. esistono delle classi che hanno associata una lista di ascoltatori (ne esiste una specifica per ogni tipo di evento per esempio TextListener), ed esistono delle classi che si iscrivono a quella lista. In questo modo ogni evento trattato dalla lista che viene intercettato dalla prima classe, viene "sentito" da tutte le classi registrate nella lista.
La novità della nuova gestione quindi consiste nell'avere più classi che possono essere interessate all'evento che si registrano come ascoltatori alla lista opportuna, e possono essere notificate tutte al momento del verificarsi dell'evento. Nella vecchia gestione invece le sole classi notificate erano quella che conteneva i metodi per la gestione dell'evento, ed eventualmente i successivi contenitori.
Un'altra novità che riguarda la nuova gestione di eventi, al di fuori dell'AWT, è la possibilità di creare eventi nuovi estendendo l'interfaccia EventObject gestiti da una nuova interfaccia ascoltatrice estensione dell'interfaccia EventListener. In uno dei capitoli successivi verrà spiegata in breve questa possibilità.
In figura 1 e 2 è rappresentata la differenza tra le due gestioni. Come potete vedere nella gestione vecchia tutti gli eventi vengono intercettati dal metodo handleEvent(), mentre nella nuova vengono intercettati solo quelli per cui esiste una lista a cui si sono registrati degli ascoltatori.
 

Figura 1.
 


Figura 2.


A chi assolutamente non ha alcun idea circa la nuova gestione, presenterò una breve storiella.
Supponiamo che io voglia far sapere un certo numero di persone la data in cui avverrà la prossima Conferenza su Java (evento = prossima Conferenza Java).
Allora ho bisogno di annotarmi tutti i dati (nominativi e indirizzi delle persone), e quindi prenderò un foglio (lista ascoltatrice) per tale scopo. Siccome anch’io sono interessata all’evento la prima cosa che farò è inserire il mio nominativo; dopo di che se conosco i dati delle persone, non farò altro che aggiungerli direttamente alla lista, altrimenti farò in modo di far avere la lista agli interessati affinché loro stessi possano aggiungere i loro dati. Naturalmente posso anche aver comunicazioni di ripensamento da parte delle persone che non vogliono più partecipare alla Conferenza; in questo caso non farò altro che cancellarle dalla lista.
Terminata la lista, non mi rimarrà che attendere il verificarsi dell’evento, e non appena l'organizzatore della conferenza mi avviserà comunicandomi la data e i dati relativi, io non farò altro che inviare un avviso postale a tutti gli indirizzi delle persone iscritte nella lista.
In questa storiella io sono la classe sorgente dell'evento, detentrice della lista ascoltatrice e quindi di tutti i metodi necessari a gestirla. Dato che le liste hanno un nome xxxxxxListener, potremmo chiamarla ProssimaConferenzaJavaListener che estende l’interfaccia EventListener. L’evento che gestirà questa lista discende come tutti gli eventi dalla classe EventObject che hanno un nome xxxxxxEvent; quindi questo evento avrà nome ProssimaConferenzaJavaEvent.
Le persone iscritte nella lista non sono altro che le istanze di classi interessate al verificarsi dell’evento e i loro dati riguardano i loro handle. Le istanze vengono inserite nella lista tramite il metodo addProssimaConferenzaJavaListener(ProssimaConferenzaJavaListener pcj) e rimosse tramite il metodo removeProssimaConferenzaJavaListener(ProssimaConferenzaJavaListener pcj)
Chi è a questo punto il responsabile dell’avviso dell’evento? Non è altro che una qualsiasi istanza di classe che mi spedisce la notifica richiamando un mio metodo, che non fa altro che spedire la notizia con tutti i dati relativi all’indirizzo specificato richiamando un metodo particolare dedicato alla gestione dell’evento considerato, per esempio potremmo chiamarlo ProssimaConferenzaJavaPerformed gestore dell'evento ProssimaConferenzaJavaEvent che è un evento che fa parte della nostra lista (ci si aspetta di trovare questo metodo associato all'handle della classe iscritta, esattamente come un postino si aspetta di trovare una casella postale all’indirizzo di riferimento) in cui vengono eseguite tutte le istruzioni che la classe iscritta aveva stabilito di fare (la persona dalla casella postale prende delle decisioni in funzione dei dati iscritti). Spiegheremo più in dettaglio questa filosofia nell'ultimo paragrafo.
 

La gestione eventi AWT con il JDK 1.0
Come accennato nell'introduzione, con la gestione degli eventi AWT 1.0 la classe che gestisce l'evento è l'unica alla quale viene notificato l'evento.
La prassi che viene seguita quando un evento occorre è spiegata di seguito.
Viene eseguita una chiamata al metodo nativo del toolkit window Container.deliverEvent() che determina che Component sorgente deve essere passato come dato dell'evento.
Quando il Component viene identificato il metodo Component.postEvent() spedisce l'evento al Component invocando il metodo handleEvent(). Qui di seguito è riportato il codice del metodo all'interno della classe Component:

public boolean handleEvent(Event evt) {

        switch (evt.id) {

          case Event.MOUSE_ENTER:

            return mouseEnter(evt, evt.x, evt.y);
 
 

          case Event.MOUSE_EXIT:

            return mouseExit(evt, evt.x, evt.y);
 
 

          case Event.MOUSE_MOVE:

            return mouseMove(evt, evt.x, evt.y);
 
 

          case Event.MOUSE_DOWN:

            return mouseDown(evt, evt.x, evt.y);
 
 

          case Event.MOUSE_DRAG:

            return mouseDrag(evt, evt.x, evt.y);
 
 

          case Event.MOUSE_UP:

            return mouseUp(evt, evt.x, evt.y);
 
 

          case Event.KEY_PRESS:

          case Event.KEY_ACTION:

            return keyDown(evt, evt.key);
 
 

          case Event.KEY_RELEASE:

          case Event.KEY_ACTION_RELEASE:

            return keyUp(evt, evt.key);
 
 

          case Event.ACTION_EVENT:

            return action(evt, evt.arg);

          case Event.GOT_FOCUS:

            return gotFocus(evt, evt.arg);

          case Event.LOST_FOCUS:

            return lostFocus(evt, evt.arg);

        }

        return false;

    }

A questo punto se la classe contenitore (esempio Applet) ha ridefinito il metodo handleEvent(), questo sarà il metodo richiamato. Esempio:

public MiaApplet extends Applet {

    ...

    Button MioBottone = new Button("OK");

    ...
 
 

    public boolean handleEvent(Event evt) {

        if (event.target == MioBottone && evt.id == Event.ACTION_EVENT) {

            // fa qualcosa

        }

        ....

    }

}

Come si può notare nell'applet il metodo handleEvent() è stato ridefinito, quindi non appena verrà cliccato sul bottone MioBottone la notifica arriverà al contenitore MiaApplet e verrà eseguito il metodo handleEvent().
In realtà la notifica arriva prima al bottone che però l'unico handleEvent() da eseguire che ha è quello del padre Component; il metodo restituisce false (tutti i metodi richiamati da handleEvent() che vedete restituiscono false) e quindi cede il controllo al contenitore cioè a MiaApplet.
Se si vuole che l'evento sia intercettato dal bottone, è necessario creare una nuova classe estensione di Button in cui ridefinire il metodo e poi istanziare questa classe all'interno dell' applet.
Esempio:
 
public NuovoBottone exteds Button {

    ...

    public boolean handleEvent(Event evt) {

    ...

    }

}
 
 
 
 

public MiaApplet extends Applet {

    ...

    NuovoBottone MioBottone = new NuovoBottone("OK");

    ...

}

A questo punto la notifica arriverà prima al bottone e poi se il metodo handleEvent() restituirà false il controllo verrà ceduto all'applet.

Per quanto riguarda l'evento, tutte le informazioni passate ai vari metodi gestori sono contenute nella classe java.awt.Event .

Nella tabella che segue sono descritte tali informazioni:
 
Variabile
Descrizione
arg Contiene specifici valori a secondo del componente. Per esempio nel caso di un TextField contiene il testo e nel caso di un CheckBox contiene lo stato.
clickCount E' il numero di click effettuati con il mouse nel caso di evento MOUSE_DOWN
evt Nel caso di piu' eventi indica quale sia il prossimo.
modifiers Mostra lo stato dei tasti speciali ALT, CTRL, META e SHIFT 

Puo' assumere i seguenti valori: 

ALT_MASK 
CTRL_MASK 
META_MASK 
SHIFT_MASK 

id Identificatore dell'evento. 

Può assumere i valori che seguono. 

ACTION_EVENT 
KEY_ACTION 
KEY_ACTION_RELEASE 
KEY_PRESS 
KEY_RELEASE 
MOUSE_DOWN 
MOUSE_DRAG 
MOUSE_ENTER 
MOUSE_EXIT 
MOUSE_MOVE 
MOUSE_UP 
SCROLL_ABSOLUTE 
SCROLL_BEGIN 
SCROLL_END 
SCROLL_LINE_DOWN 
SCROLL_LINE_UP 
SCROLL_PAGE_DOWN 
SCROLL_PAGE_UP 
WINDOW_DEICONIFY 
WINDOW_DESTROY 
WINDOW_EXPOSE 
WINDOW_ICONIFY 

key Nel caso di eventi che riguardano la tastiera identificano il codice del tasto premuto. 

Possono assumere i seguenti valori: 

F1, F2, … F12 
DOWN 
END 
HOME 
LEFT 
PGDN 
PGUP 
RIGHT 
UP

target Oggetto sorgente dell'evento
when E' l'orario in cui avviene l'evento
x, y Coordinate all'interno del componente dove l'evento occorre

 

La nuova gestione eventi AWT con il JDK 1.1
  Nella nuova gestione degli eventi, questi sono generati da una sorgente di eventi. Uno o più ascoltatori possono registrarsi per essere avvertiti quando quel particolare evento occorre. Questo modello è anche chiamato a delega perché permette al programmatore di delegare la gestione di un evento ad un determinato oggetto che implementi un'appropriata interfaccia ascoltatrice. Nel nuovo modello di eventi AWT tutti gli eventi sono estensioni della classe java.awt.AWTEvent. In figura  3 sono rappresentanti tutti gli eventi e nella tabella successiva sono raccolte le descrizioni di tali eventi.
 
 


Figura 3.


Evento
Quando viene attivato
Liste associate
Componenti coinvolti
ComponentEvent Al momento di nascondere, muovere, ridimensionare, mostrare componenti ComponentListener Component
ContainerEvent Al momento dell’aggiunta, rimozione di un componente al contenitore ContainerListener Container
FocusEvent Al momento che un componente prende o perde il fuoco FocusListener Component
KeyEvent Al momento che viene premuto, rilasciato o digitato un tasto KeyListener Component
MouseEvent Al momento che un componente viene cliccato, trascinato, o che il cursore entri, esca, o si muova sopra di esso, o che un tasto del mouse venga premuto o rilasciato. MouseListener 

MouseMotionListener

Component
WindowEvent Al momento che una finestra venga iconizzata, deiconizzata, aperta, sia in chiusura o realmente chiusa, attivata o disattivata. WindowListener Container
ActionEvent Al momento che si verifica un’azione sul componente ActionListener Button 
List 
MenuItem 
TextField
AdjustmentEvent Al momento che avvengono variazioni in una ScrollBar. AdjustmentListener ScrollBar
ItemEvent Al momento in cui cambia lo stato. ItemListener Choice 
Checkbox 
CheckboxMenuItem 
List
TextEvent Al momento che cambia un testo. TextListener TextArea 
TextField

I gestori di eventi possono essere istanze di qualsiasi classe.  Per utilizzare la nuova gestione AWT, bisogna eseguire tre passi:

  1. Scelta dell’interfaccia e in particolare dei metodi necessari. A secondo del componente e della particolare esigenza, noi abbiamo diverse interfacce, come dimostra la tabella precedente.

  2. Se per esempio abbiamo bisogno di intercettare l’evento di movimento del mouse su un determinato componente, useremo il metodo mouseMoved(MouseMovedEvent e) dell’interfaccia MouseMotionListener.

     

  3. Utilizzo dell’interfaccia associandola ad una classe di ascolto.

  4. La classe di ascolto interessata all’evento ridefinirà i metodi necessari alla gestione dell’evento, e al momento del verificarsi dello stesso, verrà eseguito il codice incluso in tali metodi. E’ possibile eseguire questa operazione in due modi. La prima possibilità consiste nell’implementare direttamente l’interfaccia, per esempio

    public class MiaClasse implements MouseMotionListener {}
    In questo modo la classe eredita tutti i metodi dell’interfaccia MouseMotionListener.
    Per esempio è possibile creare un’applet che faccia da ascoltatore a se stessa. Utilizzare questo metodo è il modo più semplice per trasformare un applet scritta con il JDK 1.0.2 in una scritta in JDK 1.1. Tutto ciò che si deve fare è scrivere un codice del seguente tipo:
     

    public class MiaApplet extends Applet implements MouseMotionListener {

        ...

        public void mouseMoved(MouseMotionEvent) {

            // codice che verrà eseguito quando avverrà l'evento

            ...

        }

        public void mouseDragged(MouseEvent e) {}
     
     

    }


    Come potete   vedere abbiamo dovuto aggiungere anche il metodo mouseDragged() anche se non ne avevamo bisogno; questa è una regola fissa che si applica quando viene implementata un’interfaccia, e cioè devono essere ridefiniti tutti i metodi di quella interfaccia. I metodi che quindi non servono non conterranno codice. Un altro modo di usare la nuova gestione è usare quella che viene chiamata adattatore di eventi (classe adapter), che equivale a creare una classe di ascolto separata dalla classe originale. Un adattatore è una classe che implementa l’interfaccia desiderata, e può essere creata direttamente implementando tale l’interfaccia, o creando una classe che estenda gli adattatori messi a disposizione nel package java.awt.event. Il vantaggio di estendere un adattatore già esistente sta nel fatto che si possono usare solo i metodi che interessano.
    Esempio con uso di implementazione di interfaccia:

    class AdattatoreCreatoDaMe implements MouseMotionListener {

        public void mouseMoved(MouseMotionEvent) {

            // codice che verrà eseguito quando avverrà l'evento

            ...

        }

        public void mouseDragged(MouseEvent e) {}
     
     

    }

    Esempio di adattatore che estende MouseMotionAdapter classe del package che implementa tutti i metodi dell’interfaccia MouseMotionListener:
    class AdattatoreCreatoDaMe extends MouseMotionAdapter {

        public void mouseMoved(MouseMotionEvent) {

            // codice che verrà eseguito quando avverrà l'evento

            ...

        }

    }

    Come si può vedere nel secondo caso non c’è stato bisogno di ridefinire il metodo mouseDragged()

     

  5. Registrazione dell’ascoltatore.

  6.  

     

    L’ultima fase consiste nella registrazione dell’ascoltatore alla lista affinché gli venga notificato l’evento. Questo si fa utilizzando i metodi che troviamo nella classe Component o in una dei suoi figli a secondo la lista scelta (vedere tabella sopra). Questi metodi avranno nome addTipoListener e removeTipoListener per rimuovere la registrazione. Quindi riprendendo l’esempio avremo addMouseMotionListener (MouseMotionListener mml) e removeMouseMotionListener (MouseMotionListener mml). Supponendo che la nostra applet MiaApplet sia interessata al movimento del cursore sul bottone MioBottone scriveremo:

    MioBottone.addMouseMotionListener(this);
    In questo modo avremo registrato l’applet (che implementa l’interfaccia MouseMotionListener) alla appostita lista ascoltatrice.
     
     
Esempio completo con la nuova gestione AWT.
Passiamo ora a considerare un esempio la cui esecuzione è qui sotto.

Clicclando sul bottone OK viene presentato un frame che la pressione del tasto Notifica non fa altro che impostare il TextField dell’applet con la dicitura "E' arrivata la notifica del clic" e nascondersi.
Il codice è stato scritto usando il JDK 1.0.2., e vedremo come trasformarlo in codice 1.1.  Sorgenti in JDK 1.0.2.:

 

//Codice dell'applet

import java.awt.*;

import java.applet.*;
 
 

public class AppletProvaEvento extends Applet {

    TextField tNotifica;

    Button bOK;
 
 

    void bOK_Clicked(Event event) {
 
 

        (new fSorgenteEvento(tNotifica)).show();

    }
 
 
 
 

    public void init() {

        super.init();

        setLayout(null);

        addNotify();

        resize(280,164);

        setBackground(new Color(170));

        tNotifica = new TextField();

        tNotifica.reshape(24,24,229,38);

        tNotifica.setBackground(new Color(16777215));

        add(tNotifica);

        bOK = new Button("OK");

        bOK.reshape(81,96,118,34);

        add(bOK);

    }
 
 

    public boolean handleEvent(Event event) {

        if (event.target == bOK && event.id == Event.ACTION_EVENT) {

            bOK_Clicked(event);

            return true;

        }

        return super.handleEvent(event);

    }

}
 
 
 
 

// Codice del frame

import java.awt.*;
 
 

public class fSorgenteEvento extends Frame {
 
 

    Button bNotifica;

    Button bEsci;

    label1;

    TextField tNotifica;
 
 

    void bNotifica_Clicked(Event event) {
 
 

        // qui viene impostato il testo sul TextField dell'applet

        tNotifica.setText("E' arrivata la notifica del clic");

        hide();

    }
 
 

    void bEsci_Clicked(Event event) {
 
 

    hide();

    }
 
 
 
 

    public fSorgenteEvento(TextField tNotifica) {

        this.tNotifica = tNotifica; // carcamento handle del TextField dell'applet

        setLayout(null);

        addNotify();

        resize(insets().left + insets().right + 347,insets().top + insets().bottom + 147);

        bNotifica = new Button("Notifica");

        bNotifica.reshape(insets().left + 36,insets().top + 96,118,34);

        add(bNotifica);

        bEsci = new Button("Esci");

        bEsci.reshape(insets().left + 204,insets().top + 96,118,34);

        add(bEsci);

        label1 = new Label("Cliccare su Notifica");

        label1.reshape(insets().left + 84,insets().top + 24,171,26);

        label1.setFont(new Font("TimesRoman", Font.BOLD, 18));

        label1.setForeground(new Color(16711680));

        add(label1);

        setTitle("Prova Notifica Clic");

    }
 
 

    public fSorgenteEvento(String title, TextField tNotifica) {

        this(tNotifica);

        setTitle(title);

    }
 
 

    public boolean handleEvent(Event event) {

        if (event.id == Event.WINDOW_DESTROY) {

            hide();

            return true;

        }

        if (event.target == bEsci && event.id == Event.ACTION_EVENT) {

            bEsci_Clicked(event);

            return true;

        }

        if (event.target == bNotifica && event.id == Event.ACTION_EVENT) {

            bNotifica_Clicked(event);

            return true;

        }

        return super.handleEvent(event);

    }

}

Come potete vedere per intervenire su un componente dell’applet dal frame, è stato necessario passare al frame l’handle di tale componente (tNotifica) creando dei costruttori appositi:

public fSorgenteEvento(TextField tNotifica) e public fSorgenteEvento(String title, TextField tNotifica)


Vediamo ora come trasformare il tutto in 1.1.  Prima di tutto sostituiamo tutti i metodi DEPRECATED. Quindi:

Cominciamo con il cambiare il codice dell’applet: osservando il programma ci rendiamo conto che l’applet è interessata a due notifiche:

Quindi visto che come evento trattiamo un’azione, le import relative alla nuova gestione:

L’unico metodo contenuto nella lista ActionListener è actionPerformed(ActionEvent event). Quindi scriveremo al posto del metodo handleEvent(Event event):
   Per registrare l’applet affinché gli arrivino le due notifiche:

 Codice finale:

import java.awt.*;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import java.applet.*;
 
 

public class AppletProvaEvento extends Applet implements ActionListener{
 
 

        TextField tNotifica;

        Button bOK;

        fSorgenteEvento sorgente;
 
 

        void bOK_Clicked(ActionEvent event) {
 
 

                 sorgente = new fSorgenteEvento();

                 sorgente.bNotifica.addActionListener(this);

                 sorgente.setVisible(true);

        }
 
 
 
 

        public void init() {

                super.init();
 
 

                setLayout(null);

                addNotify();

                setSize(280,164);

                setBackground(new Color(170));

                tNotifica = new TextField();

                tNotifica.setBounds(24,24,229,38);

                tNotifica.setBackground(new Color(16777215));

                add(tNotifica);

                bOK = new Button("OK");

                bOK.setBounds(81,96,118,34);

                add(bOK);

                bOK.addActionListener(this);

        }
 
 

        public void actionPerformed(ActionEvent event) {

                if (event.getSource() == bOK) {

                        bOK_Clicked(event);

                }

                else if (event.getSource() == sorgente.bNotifica) {

                        tNotifica.setText("E' arrivata la notifica del clic");

                        sorgente.setVisible(false);

                }

        }
 
 

}


Passiamo a considerare la classe fSorgenteEvento. Dopo aver tolto dai costruttori il parametro TextField ci accorgiamo di avere due notifiche da gestire, quella riguardanti il click sul bottone Esci e quella riguardante la chiusura della finestra (quella del bottone Notifica è intercettato dall’applet). Questa volta per poter gestire gli eventi utilizzeremo la tecnica della classe di ascolto separata, cioè quella della creazione di classi adattatori di eventi. Allora le import relative saranno:

import java.awt.event.WindowEvent;

import java.awt.event.MouseEvent;

import java.awt.event.MouseAdapter;

import java.awt.event.WindowAdapter;

Useremo due tecniche differenti: la prima tecnica la adottiamo per intercettare il click sul bottone Esci; creeremo un’istanza della classe MouseAdapter come Inner Class (classe interna, vedere articolo su Mokabyte di Ottobre 1997 ):
        // registrazione della classe fSorgenteEvento al click del bottone

        // bEsci

        bEsci.addMouseListener(

        new MouseAdapter () {

                public void mouseClicked(MouseEvent event) {

                        setVisible(false);

                }

        });

Come potete vedere la classe è specializzata sul bottone Esci e anche se avevamo altri bottoni la notifica non sarebbe certo arrivata qui. Questo è un vantaggio nell’adozione degli adapter rispetto all’avere un unico metodo dove gestire tutte le notifiche, come avveniva nell’applet. Nell’applet avevamo avuto bisogno di inserire il costrutto if per poter capire chi era la sorgente dell’evento.  La seconda tecnica la usiamo per la chiusura della finestra, consiste nel creare un’estensione della classe adapter che ci interessa (WindowAdapter). Allora avremo la nuova classe:
class MiaWindowAdapter extends WindowAdapter {

        public void windowClosing(WindowEvent event) {

                ((Frame)(event.getSource())).setVisible(false);

        }

}

Il metodo windowClosing gestisce la chiusura della finestra.

A questo punto non rimane che iscrivere questa nuova classe di ascolto:

        MiaWindowAdapter WL = new MiaWindowAdapter();

        addWindowListener(WL);
Codice finale:

import java.awt.*;

import java.awt.event.WindowEvent;

import java.awt.event.MouseEvent;

import java.awt.event.MouseAdapter;

import java.awt.event.WindowAdapter;
 
 

public class fSorgenteEvento extends Frame {
 
 

        Button bNotifica;

        Button bEsci;

        Label label1;
 
 

        public fSorgenteEvento() {
 
 

                setLayout(null);

                addNotify();

                setSize(getInsets().left + getInsets().right + 347,getInsets().top + getInsets().bottom + 147);

                bNotifica = new Button("Notifica");

                bNotifica.setBounds(getInsets().left + 33,getInsets().top + 93,118,34);

                add(bNotifica);

                bEsci = new Button("Esci");

                bEsci.setBounds(getInsets().left + 200,getInsets().top + 92,118,34);

                add(bEsci);

                label1 = new Label("Cliccare su Notifica");

                label1.setBounds(getInsets().left + 84,getInsets().top + 24,171,26);

                label1.setFont(new Font("TimesRoman", Font.BOLD, 18));

                label1.setForeground(new Color(16711680));

                add(label1);

                setTitle("Prova Notifica Clic");

                bEsci.addMouseListener(

                        new MouseAdapter () {

                                public void mouseClicked(MouseEvent event) {

                                        setVisible(false);

                                }

                        });
 
 

                MiaWindowAdapter WL = new MiaWindowAdapter();

                addWindowListener(WL);
 
 

        }
 
 
 
 
 
 

        public fSorgenteEvento(String title) {

            this();

            setTitle(title);

        }
 
 

}
 
 

class MiaWindowAdapter extends WindowAdapter {

        public void windowClosing(WindowEvent event) {

                ((Frame)(event.getSource())).setVisible(false);

        }

}
 

Nuovi eventi estensione diretta di EventObject.

Questa nuova possibilità viene utilizzata con l'introduzione dei JavaBeans.  Gli eventi permettono ad un Bean di comunicare con l'esterno e queste sono le tre parti coinvolte nella comunicazione:

Struttura della classe EventObject:
public class EventObject implements java.io.Serializable {

    protected transient Object  source;
 
 

    public EventObject(Object source) {

        if (source == null)

            throw new IllegalArgumentException("null source");
 
 

        this.source = source;

    }
 
 

    public Object getSource() {

        return source;

    }
 
 

    public String toString() {

        return getClass().getName() + "[source=" + source + "]";

    }

}
 

Gli eventi gestiti dal bean estenderanno questa classe. Riprendendo l'esempio dell'introduzione, potremmo avere un Bean ConferenzaJava gestore del seguente evento
 
// contiene i metodi che restituiscono le informazioni sull'evento

public class ProssimaConferenzaJavaEvent extends EventObject {
 
 

    private java.util.date dateEvent;

    private String[] speakers;

    private String site;
 
 

    // Data Evento

    public java.util.date getDate() {

        return dateEvent

    }
 
 

    // Luogo Evento

    public  String getSite() {

        return site

    }
 
 

    // Nominativi Speaker

    public  String[] getSpeakers() {

        return speakers

    }
 
 

    // altri metodi

    ...

    ...
 
 

}

L'interfaccia EventListener è vuota ma serve come interfaccia comune a tutti gli ascoltatori di eventi che devono estenderla.
Un ascoltatore è qualcosa che vuole essere notificato quando un evento occorre. A tutti i metodi dell'interfaccia comune vengono passati come parametri l'estensione specifica della classe EventObject.
Riprendendo l'esempio dell'introduzione avremo come interfaccia:
 

// contiene i metodi che restituiscono le informazioni sull'evento

public interface ProssimaConferenzaJavaListener extends EventListener {

    public void prossimaConferenzaJavaPerformed(ProssimaConferenzaJavaEvent e);

}

A questo punto senza una sorgente dell'evento sia ProssimaConferenzaJavaEvent che ProssimaConferenzaJavaListener rimangono non usati.  E' la sorgente dell'evento (cioè il bean) che definisce dove e quando un evento avviene. La registrazione (e la cancellazione della registrazione) a questo processo avviene tramite l'uso dei metodi

public synchronized void addTipoListener(TipoListener l)

public synchronized void removeTipoListener(TipoListener l)
A questo punto la sorgente dell'evento ha bisogno essa stessa di mantenere la lista per poterla gestire, così nel caso del   nostro esempio il codice diviene:
 

private Vector prossimaConferenzaJavaListeners = new Vector();
 
 

public synchronized void addProssimaConferenzaJavaListener(ProssimaConferenzaJavaListener l) {

    prossimaConferenzaJavaListeners.addElement(l);

}

public synchronized void removeProssimaConferenzaJavaListener(ProssimaConferenzaJavaListener l) {

    prossimaConferenzaJavaListeners.removeElement(l);

}

Facendo un paragone con l'AWT, quando si usano i suoi eventi, in questo caso non c'è problema in quanto i due metodi di add e remove sono stati già trattati nella classe Component e quindi basta semplicemente utilizzarli. Per esempio per la lista ascoltatrice ActionListener esistono già i metodi addActionListener() e removeActionListener()
Qui invece è necessario costruirli da capo.
Esiste anche la possibilità di permettere la registrazione di un solo ascoltatore (unicast) provocando l'eccezione java.util.TooManyListenersException (in questo caso non c'e' bisogno di usare la classe Vector), quando un secondo ascoltatore tenta di registrarsi.
A questo punto non appena l'evento occorre, è necessario che la sorgente dell'evento notifichi il fatto a tutti gli ascoltatori. Per il nostro esempio avremo bisogno del seguente codice:
protected void notifyProssimaConferenzaJava () {
 
 

    Vector l;

    // Crea l'evento

    ProssimaConferenzaJavaEvent pcj = new ProssimaConferenzaJavaEvent(this)
 
 

    // Copia gli ascoltatori per evitare che cambino mentre li trattiamo

    synchronized (this) {
 
 

        l = prossimaConferenzaJavaListeners.clone();

    }
 
 

    // Notifica l'evento richiamando tutti i metodi ProssimaConferenzaJavaPerformed

    // appartenenti ai vari ascoltatori.

    for (int i=0;i<l.size();i++) {

        ProssimaConferenzaJavaListener pcjl = (ProssimaConferenzaJavaListener)l.elementAt(i);

        pcjl.ProssimaConferenzaJavaPerformed(pcj);

    }

}

In questo modo vengono invocati tutti i metodi ProssimaConferenzaJavaPerformed definiti in ogni ascoltatore ed eseguito il codice relativo.
 

Conclusione.
Spero che questo articolo sia stato utile nella comprensione di questa elegante e organizzata nuova gestione degli eventi, a quanti stanno cercando di affrontare il JDK 1.1.  per la prima volta.

                                                                                                                        Daniela Ruggeri

 
 
 


MokaByte Web  1998 - www.mokabyte.it

MokaByte ricerca nuovi collaboratori. 
Chi volesse mettersi in contatto con noi può farlo scrivendo a mokainfo@mokabyte.it