Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger

Java ist auch eine Insel von Christian Ullenboom
Programmieren für die Java 2-Plattform in der Version 5 (Tiger-Release)
Buch: Java ist auch eine Insel
gp Kapitel 22 Komponenten durch Bohnen
  gp 22.1 Grundlagen der Komponententechnik
    gp 22.1.1 Brauchen wir überhaupt Komponenten?
    gp 22.1.2 Visuelle und nichtvisuelle Komponenten
    gp 22.1.3 Andere Komponententechnologien oder: Was uns Microsoft brachte
  gp 22.2 Das JavaBeans Development Kit (BDK)
    gp 22.2.1 Eine Beispielsitzung im BDK
    gp 22.2.2 Verknüpfungen zwischen Komponenten
    gp 22.2.3 Beans speichern
  gp 22.3 Die kleinste Bohne der Welt
  gp 22.4 Jar-Archive für Komponenten
  gp 22.5 Worauf JavaBeans basieren
  gp 22.6 Eigenschaften
    gp 22.6.1 Einfache Eigenschaften
    gp 22.6.2 Boolesche Eigenschaften
    gp 22.6.3 Indizierte Eigenschaften
  gp 22.7 Ereignisse
    gp 22.7.1 Multicast und Unicast
    gp 22.7.2 Namenskonvention
  gp 22.8 Weitere Eigenschaften
    gp 22.8.1 Gebundene Eigenschaften
    gp 22.8.2 Anwendung von PropertyChange bei AWT-Komponenten
    gp 22.8.3 Veto-Eigenschaften. Dagegen!
  gp 22.9 Bean-Eigenschaften anpassen
    gp 22.9.1 Customizer
  gp 22.10 Property-Editoren
  gp 22.11 BeanInfo
  gp 22.12 Beliebte Fehler


Galileo Computing

22.7 Ereignissdowntop

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, so dass 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, so wie wir es gesehen haben, meistens visuell, kann aber genauso 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.


Galileo Computing

22.7.1 Multicast und Unicast  downtop

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 Mulitcast. 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 so verhält wie eine AWT-Komponente, ist möglich, wenn wir die gleichen Spielregeln beachten. Dazu gehört, sich Gedanken über Ausnahmen im Listener zu machen. Denn tritt bei einem Listener eine Exception auf, dann kann die Ereignisquelle die Abarbeitung abbrechen oder nicht. Normalerweise sollte sie aber die anderen Interessenten berücksichtigen.


Galileo Computing

22.7.2 Namenskonvention  toptop

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 mit dem Namen <eventName>Event aus und informiert jeden Listener, der in der Liste eingetragen ist. Die Events, die gemäß den Vorgaben des Listeners implementiert werden müssen, können beliebige Namen tragen. Erlaubt die add-Methode nur einen Listener, weil sie nur Unicast erlaubt, muss sie zusätzlich java.util.TooManyListeners Exception werfen können.


Beispiel   Ein Radio wirft in regelmäßigen Abständen WerbungEvent-Objekte aus. Die Signaturen und Klassen sehen skizziert wie folgt aus:

Listing 22.4   RadioTest.java, Teil 1


import java.util.*;

class WerbungEvent extends EventObject
{
  String nameDerWerbung;

  WerbungEvent( Object source, String nameDerWerbung)
  {
    super( source );
    this.nameDerWerbung = nameDerWerbung;
  }
}

interface WerbungListener extends EventListener
{
  void werbungKommt( WerbungEvent e );
}

class Radio
{
  private Vector listeners = new Vector();

  Radio()
  {
    new Thread() {
      public void run() {
        while ( true )
          notifyWerbung( new WerbungEvent( this,
            "Jetzt platzt auch der Haarknoten"));
      }
    }.start();
  }

  public void addWerbungListener( WerbungListener listener ) {
    listeners.addElement( listener );
  }

  public void removeWerbungListener( WerbungListener listener ) {
    listeners.removeElement( listener );
  }

  protected synchronized void notifyWerbung( WerbungEvent e )
  {
    for ( int i = 0; i < listeners.size(); i++ )
     ((WerbungListener)listeners.elementAt(i)).werbungKommt(e);
  }
}

Die Schnittstelle EventListener ist im Übrigen nur eine Markierungsschnittstelle, doch alle Ereignis-Listener müssen sie erweitern.

Die Anwendung nutzt jetzt das Radio-Objekt und implementiert einen konkreten WerbungListener, etwa so:

Listing 22.5   RadioTest.java, Teil 2


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() );
  }
}

Beispiel   Löst die Bean AWT-Ereignisse aus, so 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, so dass 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 so 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

gp  static ActionListener add( ActionListener a, ActionListener b )
Verbindet Listener a und b und liefert ein neues ActionListener-Objekt zurück.
gp  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

gp  ActionEvent( Object source, int id, String command )
Erzeugt ein ActionEvent mit Quelle, die das Ereignis ausgelöst hat, einen Identifizierer und ein Kommando.




Copyright © Galileo Press GmbH 2004
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press GmbH, Gartenstraße 24, 53229 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de