Galileo Computing < openbook >
Galileo Computing - Professionelle Buecher. Auch fuer Einsteiger.
Galileo Computing - Professionelle Buecher. Auch fuer Einsteiger.


Java ist auch eine Insel von Christian Ullenboom
Buch: Java ist auch eine Insel (Galileo Computing)
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.8 Weitere Eigenschaftendowntop


Galileo Computing

22.8.1 Gebundene Eigenschaftendowntop

Die gebundenen Eigenschaften einer Bean erlauben es, andere Komponenten über eine Zustandsänderung zu informieren. Damit werden direkt Eigenschaften und Ereignisse verbunden. Die interessierten Beans empfangen vom Auslöser ein PropertyChange-Ereignis, das sie auswerten können. Die Beans lassen sich mit addPropertyChangeListener() und removePropertyChangeListener()-Methoden als Zuhörer einfügen und abhängen. Bei einer Veränderung werden alle registrierten Zuhörer durch ein PropertyChangeEvent informiert. Die Interessierten implementieren dafür PropertyChangeListener. Über dieses Ereignis-Objekt erfahren wir den alten und neuen Wert, gleichzeitig erfahren wir etwas über den Typ und den Namen der Eigenschaft. Die Zuhörer werden erst nach der Änderung des internen Zustands informiert.


Beispiel Unsere Komponente ändert den internen String über setString(). Nach der Änderung werden alle Listener informiert. Sie macht sonst nichts Großartiges.

Listing 22.6 PropertyChangeStringBean.java

import java.beans.*;
import java.awt.*;
public class PropertyChangeStringBean extends Canvas
{
  private String string = "";
  private PropertyChangeSupport changes = new PropertyChangeSupport( this );
  public void setString( String newString )
  {
    String oldString = string;
    string = newString;
    changes.firePropertyChange( "string", oldString, newString );
  }
  public String getString()
  {
    return string;
  }
  public void addPropertyChangeListener( PropertyChangeListener l ) {
    changes.addPropertyChangeListener( l );
  }
  public void removePropertyChangeListener( PropertyChangeListener l ) {
    changes.removePropertyChangeListener( l );
  }
}

Der Methode setString() kommt zentrale Bedeutung zu. Der erste Parameter von firePropertyChange() ist der Name der Eigenschaft. Er ist nur für die Änderung von Belang und hat nichts mit dem Namen der Bean-Eigenschaft gemeinsam. Die Methode informiert alle angemeldeten Zuhörer über die Änderung mit einem PropertyChangeEvent. Im Ereignis stehen der alte und der neue Stand des Werts. Angemeldete Listener können dann darauf reagieren. So könnten abhängige Klassen zum Beispiel ihr Layout daraufhin ändern.


interface java.beans.PropertyChangeListener
extends java.util.EventListener

gp void propertyChange( PropertyChangeEvent evt )
Wird aufgerufen, wenn sich die gebundene Eigenschaft ändert. Über das Property ChangeEvent erfahren wir die Quelle und den Inhalt der Eigenschaft.

class java.beans.PropertyChangeEvent
extends java.util.EventObject

gp public PropertyChangeEvent( Object source, String propertyName,
Object oldValue, Object newValue )
Erzeugt ein neues Objekt mit der Quelle, die das Ereignis auslöst, einem Namen, dem alten und dem gewünschten Wert. Die Werte werden intern in privaten Variablen gehalten und lassen sich später nicht mehr ändern.
gp String getPropertyName()
Liefert den Namen der Eigenschaft.
gp Object getNewValue()
Liefert den neuen Wert.
gp Object getOldValue()
Liefert den alten Wert.

class java.beans.PropertyChangeSupport
implements Serializable

gp PropertyChangeSupport( Object sourceBean )
Konstruiert ein PropertyChangeSupport-Objekt, welches sourceBean als auslösende Bean beachtet.
gp synchronized void addPropertyChangeListener( PropertyChangeListener listener )
Fügt einen Listener hinzu.
gp synchronized void addPropertyChangeListener( String propertyName,
PropertyChangeListener listener )
Fügt einen Listener hinzu, der nur auf Ereignisse mit dem Namen propertyName hört.
gp synchronized void removePropertyChangeListener( PropertyChangeListener listener )
Entfernt einen Listener.
gp synchronized void removePropertyChangeListener( String propertyName,
PropertyChangeListener listener )
Entfernt den Listener, der auf propertyName hörte.
gp void firePropertyChange( String propertyName, Object oldValue, Object newValue )
Informiert alle Listener über eine Werteänderung. Sind alte und neue Werte gleich, werden keine Events ausgelöst.
gp void firePropertyChange( String propertyName, int oldValue, int newValue )
void firePropertyChange( String propertyName, boolean oldValue, boolean newValue )
Varianten von firePropertyChange() mit Integer- und Boolean-Werten.
gp void firePropertyChange( PropertyChangeEvent evt )
Informiert alle Interessenten mit einem PropertyChangeEvent, indem es propertyChange() aufruft.
gp synchronized boolean hasListeners( String propertyName )
Liefert true, wenn es mindestens einen Listener für die Eigenschaft gibt.

Galileo Computing

22.8.2 Anwendung von PropertyChange bei AWT-Komponentendowntop

Selbst das AWT und besonders Swing nutzt PropertyChange-Ereignisse an einigen Stellen, an denen ein spezielles AWT-Ereignis nicht vorgesehen ist. Das gilt etwa bei Änderungen von Hintergrund, Vordergrund oder Zeichensatz. Ein Component-Ereignis deckt dies nicht ab. Damit wir auch über diese Änderungen informiert werden, fügen wir einen Listener hinzu und horchen auf »foreground«, »background« oder »font«.


Galileo Computing

22.8.3 Veto-Eigenschaften. Dagegen!toptop

Bei gebundenen Eigenschaften informieren Komponenten andere Komponenten, falls sich ein Zustand ändert. Nun kann es aber sein, dass diese Komponenten etwas dagegen haben. In diesem Fall kann die hörende Bean ihr Veto mit einer PropertyVetoException einlegen und so eine Werteänderung verhindern. Bevor wir die Änderung machen, holen wir also erst die Zustimmung dafür ein. Eine Veto-Eigenschaft ist somit der gebundenen Eigenschaft verwandt, nur dass diese nicht meckern kann. Programmieren wir eine setXXX()-Methode mit Veto, so kann der Aufrufer jetzt durch eine PropertyVetoException nach außen anzeigen, dass er dagegen war.

fireVetoableChange( String propertyName, boolean, boolean )

Beispiel Auf einem Konto-Objekt lässt sich mit setMoney() der Kontostand verändern. Wir wollen die Methode so auszeichnen, dass sie erst um Erlaubnis fragt. Der Kontostand ist intern mit value vermerkt.

private PropertyChangeSupport changes = new PropertyChangeSupport( this );
private VetoableChangeSupport vetos = new VetoableChangeSupport( this );
public void setMoney( int newMoney ) throws PropertyVetoException
{
  int old = value;
  vetos.fireVetoableChange( "money", old, newMoney );
  value = newMoney;
  changes.firePropertyChange( "money", old, newMoney );
}

Wie wir in dem Beispiel sehen, ist zusätzlich zum Veto noch eine gebundene Eigenschaft mit dabei. Das ist die Regel, damit Interessierte auch mitbekommen, dass die Änderungen für alle gültig wurden. Denn wenn einer der Kandidaten gegen die Änderung ist, dann wird der neue Stand niemals angenommen. Die Interessenten wissen ja nichts voneinander. War jedoch keiner gegen die Änderung, so bekommen sie auch alle ein PropertyChange und wissen somit, dass alles in Ordnung ist. Alle sind mit dem neuen Wert einverstanden.

Gibt es mehrere Listener, die kein Veto einlegen und aus dem Veto-Event das Ergebnis herausnehmen, hat das den Nachteil, dass ein Listener, der Veto einlegt, alles abbricht und die alten Ergebnisse ungültig macht. Glücklicherweise entschuldigt sich dann VetoableChangeSupport, indem für die schon abgearbeiteten Listener noch einmal ein Veto mit dem alten Wert geschickt wird. Implementieren wir die Behandlung selbst, so müssen wir den Zustand selbst wiederherstellen und die Hörer informieren. Jetzt dürfen keine Vetos mehr auftauchen. Wenn doch, dann sollten sie ignoriert werden. Das entspricht einem einfachen Undo. Damit diese Entschuldigung nicht erst beachtet werden muss, reicht es aus, auf die Auslösung von PropertyChange zu warten, um dann sicher zu sein, dass alle das Ergebnis akzeptiert haben. Wenn wir auf ein Veto hören, hat das den Vorteil, dass wir sukzessive den Prozess verfolgen können. Wir können so immer wieder Vorschläge einreichen und sehen, ob sie akzeptiert werden.

Obwohl der Wunsch für eine Veto-Änderung auch einen PropertyChange darstellt, ist es fehleranfällig, für Veto- und auch gebundene Eigenschaften gleichzeitig PropertyChange Event-Objekte einzusetzen. Während bei Veto-Objekten vor der Zustandsänderung ein PropertyChangeEvent erzeugt wird, informieren die gebundenen Eigenschaften nach der Änderung ihre Zuhörer mit einem PropertyChangeEvent. Daher bedeutet das Aufkommen eines PropertyChangeEvent zweimal etwas Unterschiedliches.





Copyright (c) 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