9.4 | Erzeugen eigener Ereignisse
|
In vielen Situationen reicht es nicht aus, die Komponenten
in der vordefinierten Form zu benutzen. Sie müssen
an die individuellen Anforderungen des Benutzers angepasst werden.
Dies kann z. B. der Fall sein, wenn eine Komponente auf
ein bestimmtes Ereignis reagieren soll. In den meisten Fällen ist es notwendig, eine
eigene Klasse von einer Komponente abzuleiten,
um bei komplexen Oberflächen die Ereignisabarbeitung
zu trennen.
Durch die Definition eigener Klassen wird das Programm überschaubarer und
strukturierter. Das AWT verfügt über viele vordefinierte Ereignisse, die in den
Standardklassen ausgelöst werden können. Für eine gute Trennung der Ereignisverarbeitung
von der Implementierung der Klasse, sollte man auch in benutzerdefinierten Komponenten Ereignisse definieren,
soweit dies Sinn macht.
Bei der Implementierung eines benutzerdefinierten Ereignisses wird prinzipiell folgendermaßen
vorgegangen:
- Zunächst sollte man ein Objekt definieren, das das Ereignis repräsentiert.
Dieses Objekt sollte von EventObject abgeleitet sein und alle
Informationen speichern, die für das Ereignis wichtig sind (im AWT z. B. ActionEvent).
- Es sollte ein Interface definiert werden, das von EventListener
abgeleitet ist und Methoden definiert, die bei Eintritt des Ereignisses aufgerufen werden
(im AWT z. B. ActionListener). Alle definierten Methoden erhalten einen Parameter vom
Typ, der das neue Ereignis repräsentiert.
- Ein Objekt, das das neu definierte Ereignis auslösen kann, sollte Methoden zur
Verfügung stellen, damit sich Listener anmelden bzw. wieder entfernen können.
Diese Methoden heissen üblicherweise addXXXListener()
bzw. removeXXXListener(), wobei XXX als Platzhalter für den
Namen des Events steht. Die Methoden verfügen über einen Parameter vom Typ
des neue definierten EventListener-Interfaces.
(im AWT ist z. B. addActionListener() bzw. removeActionListener()
in der Klasse Button definiert).
- Tritt in der neuen Komponente nun das neue Ereignis ein, muss es alle Komponente, die sich
als Event-Listener registriert haben über den Eintritt des Ereignisses informieren
(Diese geschieht im AWT bei einem ActionListener z. B. durch den Aufruf
von actionPerformed()).
In diesem Abschnitt wird die Implementierung einer Klasse demonstriert, die
zur Passworteingabe verwendet wird. Die visuelle Repräsentation erfolgt in Form
eines Textfelds.
Bei jeder Eingabe in das Textfeld wird ein Stern ausgegeben, damit das
eingegebene Passwort nicht gesehen werden kann.
Komponenten, die über den Erfolg oder Misserfolg einer Passworteingabe informiert
werden wollen, müssen sich bei dem Textfeld registrieren. Wird eine Passworteingabe
durch Drücken der return-Taste abgeschlossen, werden alle registrieren
Event-Listener über das Ereignis informiert.
Im folgenden werden die oben genannten Schritt an diesem Beispiel demonstriert.
Die Definition des Event-Objekts ist recht einfach:
public class AuthentificationEvent extends EventObject {
public final static int AUTHENTIFICATION_SUCCEEDED = 10001;
public final static int AUTHENTIFICATION_FAILED = 10002;
protected int id;
protected String password;
public AuthentificationEvent(Object source, int id, String password) {
super(source);
this.id = id;
this.password = password;
}
int getID() {
return id;
}
String getPassword() {
return password;
}
}
Die Klasse AuthentificationEvent enthält Informationen über eine
Passworteingabe. Der Konstruktor erhält das Passwort übergeben, das vom Benutzer
eingegeben wurde und einen Verweis auf das Objekt, in dem das Ereignis stattgefunden hat.
Außerdem wird eine ID gespeichert, die anzeigt, ob das eingegebene Passwort korrekt oder
falsch war. Als Werte für diese ID werden zwei Konstanten definiert.
Im EventListener-Interface werden zwei Methoden definiert:
public interface AuthentificationListener extends EventListener {
public void authentificationSucceeded(AuthentificationEvent e);
public void authentificationFailed(AuthentificationEvent e);
}
Dieses Interface muss; von Objekten implementiert werden, die über den Status einer
Passworteingabe informiert werden wollen. authentificationSucceeded()
wird bei Eingabe des richtigen Passworts, authentificationFailed()
bei Eingabe des falschen Passworts aufgerufen.
PasswordTextField ist die Klasse, die die eigentliche Komponente darstellt.
public PasswordTextField(String password) {
// Speichern des Passwortes
this.password = password;
// Stern als Ausgabezeichen setzen
setEchoChar('*');
enableEvents(AWTEvent.ACTION_EVENT_MASK);
multicaster = new AuthentificationEventMulticaster();
}
Der Konstruktor der Klasse bekommt das richtige Passwort übergeben und merkt es sich in einem
Datenelement. Außerdem wird dort ein Exemplar der Klasse
AuthentificationEventMulticaster erzeugt und ebenfalls in einem
Datenelement gespeichert. Diese Klasse ist später für das Verteilen
der Ereignisse an die unterschiedlichen Listener zuständig.
Mit folgenden Methoden können sich die Listener bei dem Textfeld für die Passworteingabe
registrieren bzw. wieder abmelden:
public void addAuthentificationListener(
AuthentificationListener l) {
multicaster.add(l);
}
public void removeActionListener(
AuthentificationListener l) {
multicaster.remove(l);
}
Wie zu sehen ist, werden die neuen Listener an den AuthentificationEventMulticaster
weitergeleitet. Dort erfolgt also die Verwaltung der Listener.
Da die hier vorgestellte Klasse eine eigenständige Komponente darstellt, wird die
interne Ereignisverarbeitung durch die processXXXEvent()-Methoden
vorgenommen.
Nach Abschluss einer Eingabe in das Textfeld durch Drücken der Return-Taste
muss geprüft werden, ob der eingegebene Text mit dem
Passwort übereinstimmt, das dem Konstruktor übergeben
wurde.
Hierfür ist lediglich die Implementierung der Methode processActionEvent()
notwendig:
public void processActionEvent(ActionEvent e) {
// Ist das Passwort gleich dem Eingabetext?
if (password.equals(e.getActionCommand()))
// Wenn ja, Passwort korrekt
multicaster.authentificationSucceeded(
new AuthentificationEvent(this,
AuthentificationEvent.AUTHENTIFICATION_SUCCEEDED,
e.getActionCommand()));
else
// Sonst Passwort nicht korrekt
multicaster.authentificationFailed(
new AuthentificationEvent(this,
AuthentificationEvent.AUTHENTIFICATION_FAILED,
e.getActionCommand()));
if(clearAfterInput)
setText("");
}
Stimmt die Eingabe mit dem Passwort überein, müssen alle Event-Listener entsprechend darüber
informiert werden. Hierzu wird die Methode authentificationSucceeded()
des AuthentificationEventMulticaster aufgerufen. Als Argument wird ein neues
Exemplar der Klasse AuthentificationEvent übergeben, initialisiert mit
den entsprechenden Parametern. Analoges gilt für die falsche Eingabe eines Passworts.
AuthentificationEventMulticaster ist eine Klasse, die selbst
das Interface AuthentificationListener implementiert. Deshalb werden dort
ebenfalls, wie in allen anderen Event-Listenern auch, die Methoden authentificationSucceeded()
und authentificationFailed() implementiert. In dieser Implementierung wird
jedoch lediglich das neu erzeugte Exemplar von AuthentificationEvent an
alle registrierten Listener verteilt:
public class AuthentificationEventMulticaster
implements AuthentificationListener {
protected Vector listener = new Vector();
public void remove(AuthentificationListener l) {
listener.remove(l);
}
public void authentificationSucceeded(
AuthentificationEvent e) {
for(int i=0; i < listener.size(); i++)
((AuthentificationListener)listener.elementAt(i)).
authentificationSucceeded(e);
}
public void authentificationFailed(
AuthentificationEvent e) {
for(int i=0; i < listener.size(); i++)
((AuthentificationListener)listener.elementAt(i)).
authentificationFailed(e);
}
public void add(AuthentificationListener a) {
if(! listener.contains(a))
listener.addElement(a);
}
}
Hierdurch erfolgt das Verteilen des Event-Objektes transparent für die eigentliche Komponente,
da die Verwaltung der Listener komplett in eine eigene Klasse ausgelagert wurde.
Die Klasse AuthentificationEventMulticaster aus diesem Beispiel ist nicht besonders ökonomisch, dafür aber relativ leicht verständlich implementiert. Im Paket java.awt ist die Klasse
AWTEventMulticaster definiert, die einen viel effizienteren Mechanismus für das
Verteilen von Ereignissen bereitstellt. Durch diese Klassen werden alle Ereignisse im AWT an die
Event-Listener geschickt.
Material zum Beispiel
Copyright © 2002 dpunkt.Verlag, Heidelberg. Alle Rechte vorbehalten.