22.7 Ereignisse
 
Ereignisse informieren Objekte über Zustandsänderungen anderer Objekte. Auch unsere Beans können Statusmeldungen absetzen. Komponenten können in einem Application-Builder untereinander verbunden werden, sodass eine Komponente als Quelle für Ereignisse dient und Zuhörer dieses Ereignis abfangen und auswerten können. Die Zuhörer heißen im Folgenden auch Interessenten.
Die Verknüpfung der Ereignisse ist, wie wir es gesehen haben, meistens visuell, kann aber ebenso gut von Hand programmiert werden. Für die Benutzung unterscheiden sich die Bean-Ereignisse nicht von AWT-Ereignissen, die wir schon oft verwendet haben; nur treten wir hier als Anbieter (Implementierer) auf und nicht als Nutzer. Obwohl in der Regel die Interessenten eine Schnittstelle implementieren, können wir auch Adaptoren anbieten.
22.7.1 Multicast und Unicast
 
Normalerweise können mit einer Komponente beliebig viele Zuhörer verbunden werden. Tritt ein Ereignis auf, dann informiert die Komponente alle Interessierten. Dies nennt sich Multicast. Eine Einschränkung davon ist Unicast: dann darf sich nur ein Interessent anmelden. Versucht es ein zweiter, wird eine Ausnahme ausgelöst.
Dass sich also unsere Bean wie eine AWT-Komponente verhält, ist möglich, wenn wir die gleichen Spielregeln beachten. Dazu gehört auch, sich Gedanken über Ausnahmen im Listener zu machen. Tritt nämlich bei einem Listener eine Exception auf, kann die Ereignisquelle die Abarbeitung abbrechen oder nicht. Normalerweise sollte sie aber die anderen Interessenten berücksichtigen.
22.7.2 Namenskonvention
 
Genau wie für Eigenschaften gibt es für Ereignisse und die damit verbundenen Schnittstellen eigene Namenskonventionen. Interessierte Objekte sollen die Bean-Methoden add<Bean>Listener() und remove<Bean>Listener() aufrufen können. Die Bean löst ihrerseits ein Ereignis namens <eventName>Event aus und informiert jeden Listener, der in der Liste eingetragen ist. Die gemäß den Vorgaben des Listeners implementierten Events können beliebige Namen tragen. Erlaubt die add-Methode nur einen Listener, weil sie nur Unicast gestattet, so muss sie zusätzlich java.util.TooManyListenersException werfen können.
Ein Radio soll WerbungEvent-Objekte aussenden. Wir beginnen mit der Klasse WerbungEvent und WerbungListener.
Listing 22.4
RadioTest.java, Teil 1
import java.util.EventListener;
import java.util.EventObject;
import javax.swing.event.EventListenerList;
class WerbungEvent extends EventObject
{
String nameDerWerbung;
WerbungEvent( Object source, String nameDerWerbung)
{
super( source );
this.nameDerWerbung = nameDerWerbung;
}
}
interface WerbungListener extends EventListener
{
void werbungKommt( WerbungEvent e );
}
Die Schnittstelle EventListener ist im Übrigen nur eine Markierungsschnittstelle, doch alle Ereignis-Listener müssen sie erweitern.
Das Radio soll nun Interessenten an- und abmelden können. Es sendet in einem Thread Werbenachrichten:
Listing 22.5
RadioTest.java, Teil 2
class Radio
{
private EventListenerList listeners = new EventListenerList();
Radio()
{
new Thread() {
@Override
public void run() {
while ( true )
notifyWerbung( new WerbungEvent( this, "Jetzt platzt auch der Haarknoten"));
}
}.start();
}
public void addWerbungListener( WerbungListener listener ) {
listeners.add( WerbungListener.class, listener );
}
public void removeWerbungListener( WerbungListener listener ) {
listeners.remove( WerbungListener.class, listener );
}
protected synchronized void notifyWerbung( WerbungEvent e )
{
for ( WerbungListener l : listeners.getListeners(WerbungListener.class) )
l.werbungKommt(e);
}
}
Die Demo-Anwendung nutzt das Radio-Objekt und implementiert einen konkreten WerbungListener, etwa so:
Listing 22.6
RadioTest.java, Teil 3
class MyWerbungListener implements WerbungListener
{
public void werbungKommt( WerbungEvent e )
{
System.out.println( "Oh nein, schon wieder Werbung: " + e.nameDerWerbung );
}
}
public class RadioTest
{
public static void main( String[] args )
{
Radio r = new Radio();
r.addWerbungListener( new MyWerbungListener() );
}
}
AWTEventMulticaster
Löst die Bean AWT-Ereignisse aus, kann sie dafür AWTEventMulticaster nutzen. Diese Klasse ist für effizientes Multicast-Benachrichtigen bei AWT-Ereignissen gedacht. Genau genommen verbindet sie dazu nur zwei EventListener miteinander, sodass eine Verkettung entsteht.
protected ActionListener listeners;
public void addActionListener( ActionListener l ) {
listeners = AWTEventMulticaster.add( l, listeners );
}
public void removeActionListener( ActionListener l ) {
listeners = AWTEventMulticaster.remove( l, listeners );
}
Da AWTEventMulticaster alle möglichen AWT-Listener implementiert, können wir die Methode actionPerformed(), die die Schnittstelle ActionListener vorschreibt, aufrufen. Wenn wir ACTION_PERFORMED-Nachrichten damit generieren, schreiben wir Folgendes in unsere Bean-Klasse.
protected void fireActionEvent () {
if ( listeners != null )
listeners.actionPerformed(
new ActionEvent( this, ActionEvent.ACTION_PERFORMED, null) );
}
Die angemeldeten Listener bekommen auf diese Weise ein ActionEvent geliefert. Der letzte Parameter im Konstruktor, der hier mit null belegt ist, kann zusätzlich eine Referenz übermitteln.
class java.awt.event. AWTEventMulticaster
implements ComponentListener, ContainerListener, FocusListener, KeyListener, MouseListener,
MouseMotionListener, WindowListener, ActionListener, ItemListener, AdjustmentListener, TextListener,
InputMethodListener, HierarchyListener, HierarchyBoundsListener
|
|
static ActionListener add( ActionListener a, ActionListener b )
Verbindet Listener a und b und liefert ein neues ActionListener-Objekt zurück. |
|
static ActionListener remove( ActionListener l, ActionListener oldl )
Entfernt Listener oldl von l und liefert den neuen Multicast-Listener zurück. |
class java.awt.event. ActionEvent
extends AWTEvent
|
|
ActionEvent( Object source, int id, String command )
Erzeugt ein ActionEvent mit Quelle, die das Ereignis ausgelöst hat, einen Identifizierer und ein Kommando. |
|