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.
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 MOUSEDOWN | | 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: ALTMASK <br> CTRLMASK <br> METAMASK <br> SHIFTMASK | | id | Identificatore dell'evento. Può assumere i valori che seguono. ACTIONEVENT <br> KEYACTION <br> KEYACTIONRELEASE <br> KEYPRESS <br> KEYRELEASE <br> MOUSEDOWN <br> MOUSEDRAG <br> MOUSEENTER <br> MOUSEEXIT <br> MOUSEMOVE <br> MOUSEUP <br> SCROLLABSOLUTE <br> SCROLLBEGIN <br> SCROLLEND <br> SCROLLLINEDOWN <br> SCROLLLINEUP <br> SCROLLPAGEDOWN <br> SCROLLPAGEUP <br> WINDOWDEICONIFY <br> WINDOWDESTROY <br> WINDOWEXPOSE <br> WINDOWICONIFY | | key | Nel caso di eventi che riguardano la tastiera identificano il codice del tasto premuto. Possono assumere i seguenti valori: F1, F2, … F12 <br> DOWN <br> END <br> HOME <br> LEFT <br> PGDN <br> PGUP <br> RIGHT <br> 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.
| 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 <br> List <br> MenuItem <br> TextField | | AdjustmentEvent | Al momento che avvengono variazioni in una ScrollBar. | AdjustmentListener | ScrollBar | | ItemEvent | Al momento in cui cambia lo stato. | ItemListener | Choice <br> Checkbox <br> CheckboxMenuItem <br> List | | TextEvent | Al momento che cambia un testo. | TextListener | TextArea <br> TextField |
I gestori di eventi possono essere istanze di qualsiasi classe. Per utilizzare la nuova gestione AWT, bisogna eseguire tre passi:
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.
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.
Utilizzo dell’interfaccia associandola ad una classe di ascolto
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()
Registrazione dell’ascoltatore
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:
- insets() diventa getInsets()
- resize() diventa setSize()
- reshape() diventa setBounds()
- hide() divenda setVisible(false)
- show() divenda setVisible(true)
Cominciamo con il cambiare il codice dell’applet: osservando il programma ci rendiamo conto che l’applet è interessata a due notifiche:
- quella che si ha cliccando sul bottone OK
- quella che si ha cliccando sul bottone Notifica del frame.
Quindi visto che come evento trattiamo un’azione, le import relative alla nuova gestione:
- import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
L’unico metodo contenuto nella lista ActionListener è actionPerformed(ActionEvent event). Quindi scriveremo al posto del metodo handleEvent(Event event):
- public void actionPerformed(ActionEvent event) {
if (event.getSource() == bOK) {
// Click sul bottone OK
bOK_Clicked(event);
}
else if (event.getSource() == sorgente.bNotifica) {
// Click sul bottone notifica del frame
tNotifica.setText("E' arrivata la notifica del clic");
sorgente.setVisible(false);
}
}
Per registrare l’applet affinché gli arrivino le due notifiche:
- per la notifica circa il bottone OK basta inserire nel metodo init() l’istruzione
bOK.addActionListener(this);
per la notifica circa il bottone OK basta inserire nel metodo bOK_Clicked(Event event) sotto la creazione dell’istanza del frame l’istruzione
sorgente.bNotifica.addActionListener(this);
sorgente.setVisible(true);
Come potete vedere abbiamo spostato il codice da eseguire dal frame all’applet. Allora a questo punto non abbiamo più bisogno di passare l’handle del campo notifica al frame, quindi torniamo ai vecchi costruttori del frame. Per istanziare avremo:
sorgente = new fSorgenteEvento();
dove sorgente è l’istanza di fSorgenteEvento.
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 [](../../1997/10/index.htm)
):
// 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:
- EventObject . L'evento
- EventListener. La lista.
- La sorgente dell'evento, cioè il bean.
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
