Tit   Inh   Ind   1   2   3   4   5   6   7   8   9   10   11   12   13   14   15   16   17   18   19   20   21   22   23   24   25   26   27   28   29   30   31   32   <<   <   >   >> 

18.2 Entwurfsmuster für den Nachrichtenverkehr



Wir wollen uns in diesem Abschnitt damit beschäftigen, die oben erwähnten Entwurfsmuster für die Abwicklung des Nachrichtenverkehrs in Java-Programmen vorzustellen. Wie bereits erwähnt, hat jedes dieser Verfahren seine ganz spezifischen Vor- und Nachteile und ist für verschiedene Programmieraufgaben unterschiedlich gut geeignet.

Als Basis für unsere Experimente wollen wir ein einfaches Programm schreiben, das die folgenden Anforderungen erfüllt:

  • Nach dem Start soll das Programm ein Fenster mit dem Titel »Nachrichtentransfer« auf dem Bildschirm anzeigen.
  • Das Fenster soll einen grauen Hintergrund haben und in der Client-Area die Meldung »Zum Beenden bitte ESC drücken ...« anzeigen.
  • Nach Drücken der Taste [ESC] soll das Fenster geschlossen und das Programm beendet werden. Andere Tastendrücke, Mausklicks oder ähnliche Ereignisse werden ignoriert.

Basis der Programme ist das folgende Listing:

001 /* Listing1801.java */
002 
003 import java.awt.*;
004 import java.awt.event.*;
005 
006 public class Listing1801
007 extends Frame
008 {
009    public static void main(String[] args)
010    {
011       Listing1801 wnd = new Listing1801();
012    }
013 
014    public Listing1801()
015    {
016       super("Nachrichtentransfer");
017       setBackground(Color.lightGray);
018       setSize(300,200);
019       setLocation(200,100);
020       setVisible(true);
021    }
022 
023    public void paint(Graphics g)
024    {
025       g.setFont(new Font("Serif",Font.PLAIN,18));
026       g.drawString("Zum Beenden bitte ESC drücken...",10,50);
027    }
028 }
Listing1801.java
Listing 18.1: Basisprogramm für den Nachrichtentransfer

 Beispiel 

Das Programm erfüllt die ersten der oben genannten Anforderungen, ist aber mangels Event-Handler noch nicht in der Lage, per [ESC] beendet zu werden. Um die Nachfolgeversionen vorzubereiten, haben wir bereits die Anweisung import java.awt.event.* eingefügt.

 Hinweis 

Die Ausgabe des Programms ist:

Abbildung 18.3: Das Programm für den Nachrichtentransfer

18.2.1 Variante 1: Implementierung eines EventListener-Interfaces

Bei der ersten Variante gibt es nur eine einzige Klasse, Listing1802. Sie ist einerseits eine Ableitung der Klasse Frame, um ein Fenster auf dem Bildschirm darzustellen und zu beschriften. Andererseits implementiert sie das Interface KeyListener, das die Methoden keyPressed, keyReleased und keyTyped definiert. Der eigentliche Code zur Reaktion auf die Taste [ESC] steckt in der Methode keyPressed, die immer dann aufgerufen wird, wenn eine Taste gedrückt wurde. Mit der Methode getKeyCode der Klasse KeyEvent wird auf den Code der gedrückten Taste zugegriffen und dieser mit der symbolischen Konstante VK_ESCAPE verglichen. Stimmen beide überein, wurde [ESC] gedrückt, und das Programm kann beendet werden.

001 /* Listing1802.java */
002 
003 import java.awt.*;
004 import java.awt.event.*;
005 
006 public class Listing1802
007 extends Frame
008 implements KeyListener
009 {
010    public static void main(String[] args)
011    {
012       Listing1802 wnd = new Listing1802();
013    }
014 
015    public Listing1802()
016    {
017       super("Nachrichtentransfer");
018       setBackground(Color.lightGray);
019       setSize(300,200);
020       setLocation(200,100);
021       setVisible(true);
022       addKeyListener(this);
023    }
024 
025    public void paint(Graphics g)
026    {
027       g.setFont(new Font("Serif",Font.PLAIN,18));
028       g.drawString("Zum Beenden bitte ESC drücken...",10,50);
029    }
030 
031    public void keyPressed(KeyEvent event)
032    {
033       if (event.getKeyCode() == KeyEvent.VK_ESCAPE) {
034          setVisible(false);
035          dispose();
036          System.exit(0);
037       }
038    }
039 
040    public void keyReleased(KeyEvent event)
041    {
042    }
043 
044    public void keyTyped(KeyEvent event)
045    {
046    }
047 }
Listing1802.java
Listing 18.2: Implementieren eines Listener-Interfaces

Die Verbindung zwischen der Ereignisquelle (in diesem Fall der Fensterklasse Listing1802) und dem Ereignisempfänger (ebenfalls die Klasse Listing1802) erfolgt über den Aufruf der Methode addKeyListener der Klasse Frame. Alle Tastaturereignisse werden dadurch an die Fensterklasse selbst weitergeleitet und führen zum Aufruf der Methoden keyPressed, keyReleased oder keyTyped des Interfaces KeyListener. Diese Implementierung ist sehr naheliegend, denn sie ist einfach zu implementieren und erfordert keine weiteren Klassen. Nachteilig ist dabei allerdings:

Es bleibt festzuhalten, daß diese Technik bestenfalls für kleine Programme geeignet ist, die nur begrenzt erweitert werden müssen. Durch die Vielzahl leerer Methodenrümpfe können aber auch kleine Programme schnell unübersichtlich werden.

18.2.2 Variante 2: Lokale und anonyme Klassen

Die zweite Alternative ist eine bessere Lösung. Sie basiert auf der Verwendung lokaler bzw. anonymer Klassen und kommt ohne die Nachteile der vorigen Version aus. Sie ist das in der Dokumentation des JDK empfohlene Entwurfsmuster für das Event-Handling in kleinen Programmen oder bei Komponenten mit einfacher Nachrichtenstruktur. Vor ihrem Einsatz sollte man allerdings das Prinzip lokaler und anonymer Klassen kennenlernen, das mit dem JDK 1.1 in Java eingeführt wurde. Wir wollen es hier kurz vorstellen, uns dabei aber lediglich mit den Grundzügen dieser Technik beschäftigen, um den Einsatz für die Ereignisbehandlung aufzuzeigen. Ein weiteres Beispiel für die Verwendung lokaler Klassen findet sich in Abschnitt 27.4.

Lokale Klassen

Bis zum JDK 1.0 wurden Klassen immer auf der Paketebene definiert, eine Schachtelung war nicht möglich. Seit JDK 1.1 gibt es die Möglichkeit, innerhalb einer bestehenden Klasse X eine neue Klasse Y zu definieren (im JDK wird das gesamte Konzept als Inner Classes bezeichnet). Diese Klasse unterliegt lexikalischen Sichtbarkeitsregeln und ist nur innerhalb von X sichtbar. Objektinstanzen von Y können damit auch nur aus X erzeugt werden. Anders herum (und das macht die lokalen Klassen für das Event-Handling interessant) kann Y auf alle Membervariablen von X zugreifen. Bei der Instanzierung wird (neben einem impliziten this-Zeiger) ein weiterer Verweis auf die erzeugende Instanz der umschließenden Klasse übergeben, der es ermöglicht, auf sie zuzugreifen.

Die Anwendung lokaler Klassen für die Ereignisbehandlung besteht darin, mit ihrer Hilfe die benötigten EventListener zu implementieren. Dazu wird in dem GUI-Objekt, das einen Event-Handler benötigt, eine lokale Klasse definiert und aus einer passenden Adapterklasse abgeleitet. Nun braucht nicht mehr das gesamte Interface implementiert zu werden (denn die Methodenrümpfe werden ja aus der Adapterklasse geerbt), sondern lediglich die tatsächlich benötigten Methoden. Da die lokale Klasse zudem auf die Membervariablen und Methoden der Klasse zugreifen kann, in der sie definiert wurde, lassen sich auf diese Weise sehr schnell die benötigten Ereignisempfänger zusammenbauen.

Das folgende Beispiel definiert eine lokale Klasse MyKeyListener, die aus KeyAdapter abgeleitet wurde und auf diese Weise das KeyListener-Interface implementiert. Sie überlagert lediglich die Methode keyPressed, um auf das Drücken einer Taste zu reagieren. Als lokale Klasse hat sie außerdem Zugriff auf die Methoden der umgebenden Klasse und kann somit durch Aufruf von setVisible und dispose das Fenster, in dem sie als Ereignisempfänger registriert wurde, schließen. Die Registrierung der lokalen Klasse erfolgt durch Aufruf von addKeyListener, bei dem gleichzeitig eine Instanz der lokalen Klasse erzeugt wird. Als lokale Klasse ist MyKeyListener überall innerhalb von Listing1803 sichtbar und kann an beliebiger Stelle instanziert werden.

001 /* Listing1803.java */
002 
003 import java.awt.*;
004 import java.awt.event.*;
005 
006 public class Listing1803
007 extends Frame
008 {
009    public static void main(String[] args)
010    {
011       Listing1803 wnd = new Listing1803();
012    }
013 
014    public Listing1803()
015    {
016       super("Nachrichtentransfer");
017       setBackground(Color.lightGray);
018       setSize(300,200);
019       setLocation(200,100);
020       setVisible(true);
021       addKeyListener(new MyKeyListener());
022    }
023 
024    public void paint(Graphics g)
025    {
026       g.setFont(new Font("Serif",Font.PLAIN,18));
027       g.drawString("Zum Beenden bitte ESC drücken...",10,50);
028    }
029 
030    class MyKeyListener
031    extends KeyAdapter
032    {
033       public void keyPressed(KeyEvent event)
034       {
035          if (event.getKeyCode() == KeyEvent.VK_ESCAPE) {
036             setVisible(false);
037             dispose();
038             System.exit(0);
039          }
040       }
041    }
042 }
Listing1803.java
Listing 18.3: Verwendung lokaler Klassen

 Beispiel 

Der Vorteil dieser Vorgehensweise ist ganz offensichtlich: es werden keine unnützen Methodenrümpfe erzeugt, aber trotzdem verbleibt der Ereignisempfängercode wie im vorigen Beispiel innerhalb der Ereignisquelle. Dieses Verfahren ist also immer dann gut geeignet, wenn es von der Architektur oder der Komplexität der Ereignisbehandlung her sinnvoll ist, Quelle und Empfänger zusammenzufassen.

Anonyme Klassen

Eine Variante der lokalen Klassen sind die anonymen Klassen. Sie werden ebenfalls lokal zu einer anderen Klasse erzeugt, kommen aber ohne Klassennamen aus. Dazu werden sie bei der Übergabe eines Objektes an eine Methode oder als Rückgabewert einer Methode innerhalb einer einzigen Anweisung definiert und instanziert. Damit eine anonyme Klasse überhaupt irgendeiner sinnvollen Aufgabe zugeführt werden kann, muß sie aus einer anderen Klasse abgeleitet sein oder ein bestehendes Interface implementieren.

Sowohl einfache lokale Klassen als auch anonyme lokale Klassen wurden realisiert, ohne daß eine Änderung der virtuellen Maschine erforderlich war. Statt dessen wurde die Implementierung dieses Konzepts vollständig dem Java-Compiler übertragen. Im Falle einer lokalen Klasse Y innerhalb einer Klasse X erzeugt der Compiler beim Übersetzen der Quelldatei Klassennamen der Art X$Y.class. Im Falle einer anonymen Klasse innerhalb von X erzeugt er Code der Art X$1.class, X$2.class usw. Das Laufzeitsystem interpretiert die lokale Klasse wie eine nicht-lokale.

 Hinweis 

Das folgende Beispiel ist eine leichte Variation des vorigen Beispiels. Es zeigt die Verwendung einer anonymen Klasse, die aus KeyAdapter abgeleitet wurde, als Ereignisempfänger. Zum Instanzierungszeitpunkt erfolgt die Definition der überlagerten Methode keyPressed, in der der Code zur Reaktion auf das Drücken der Taste [ESC] untergebracht wird.

001 /* Listing1804.java */
002 
003 import java.awt.*;
004 import java.awt.event.*;
005 
006 public class Listing1804
007 extends Frame
008 {
009    public static void main(String[] args)
010    {
011       Listing1804 wnd = new Listing1804();
012    }
013 
014    public Listing1804()
015    {
016       super("Nachrichtentransfer");
017       setBackground(Color.lightGray);
018       setSize(300,200);
019       setLocation(200,100);
020       setVisible(true);
021       addKeyListener(
022          new KeyAdapter() {
023             public void keyPressed(KeyEvent event)
024             {
025                if (event.getKeyCode() == KeyEvent.VK_ESCAPE) {
026                   setVisible(false);
027                   dispose();
028                   System.exit(0);
029                }
030             }
031          }
032       );
033    }
034 
035    public void paint(Graphics g)
036    {
037       g.setFont(new Font("Serif",Font.PLAIN,18));
038       g.drawString("Zum Beenden bitte ESC drücken...",10,50);
039    }
040 
041 }
Listing1804.java
Listing 18.4: Verwendung anonymer Klassen

 Beispiel 

Vorteilhaft bei dieser Vorgehensweise ist der verringerte Aufwand, denn es muß keine separate Klassendefinition angelegt werden. Statt dessen werden die wenigen Codezeilen, die zur Anpassung der Adapterklasse erforderlich sind, dort eingefügt, wo die Klasse instanziert wird, nämlich beim Registrieren des Nachrichtenempfängers. Anonyme Klassen haben einen ähnlichen Einsatzbereich wie lokale, empfehlen sich aber vor allem, wenn sehr wenig Code für den Ereignisempfänger benötigt wird. Bei aufwendigeren Ereignisempfängern ist die explizite Definition einer benannten Klasse dagegen vorzuziehen.

18.2.3 Variante 3: Trennung von GUI- und Anwendungscode

Wir hatten am Anfang darauf hingewiesen, daß in größeren Programmen eine Trennung zwischen Programmcode, der für die Oberfläche zuständig ist, und solchem, der für die Anwendungslogik zuständig ist, wünschenswert wäre. Dadurch wird eine bessere Modularisierung des Programms erreicht, und der Austausch oder die Erweiterung von Teilen des Programms wird erleichtert.

Das Delegation Event Model wurde auch mit dem Designziel entworfen, eine solche Trennung zu ermöglichen bzw. zu erleichtern. Der Grundgedanke dabei war es, auch Nicht-Komponenten die Reaktion auf GUI-Events zu ermöglichen. Dies wurde dadurch erreicht, daß jede Art von Objekt als Ereignisempfänger registriert werden kann, solange es die erforderlichen Listener-Interfaces implementiert. Damit ist es möglich, die Anwendungslogik vollkommen von der grafischen Oberfläche abzulösen und in Klassen zu verlagern, die eigens für diesen Zweck entworfen wurden.

 Hinweis 

Das nachfolgende Beispiel zeigt diese Vorgehensweise, indem es unser Beispielprogramm in die drei Klassen Listing1805, MainFrameCommand und MainFrameGUI aufteilt. Listing1805 enthält nur noch die main-Methode und dient lediglich dazu, die anderen beiden Klassen zu instanzieren. MainFrameGUI realisiert die GUI-Funktionalität und stellt das Fenster auf dem Bildschirm dar. MainFrameCommand spielt die Rolle des Kommandointerpreters, der immer dann aufgerufen wird, wenn im Fenster ein Tastaturereignis aufgetreten ist.

Die Verbindung zwischen beiden Klassen erfolgt durch Aufruf der Methode addKeyListener in MainFrameGUI, an die das an den Konstruktor übergebene MainFrameCommand-Objekt weitergereicht wird. Dazu ist es erforderlich, daß das Hauptprogramm den Ereignisempfänger cmd zuerst instanziert, um ihn bei der Instanzierung des GUI-Objekts gui übergeben zu können.

Umgekehrt benötigt natürlich auch das Kommando-Objekt Kenntnis über das GUI-Objekt, denn es soll ja das zugeordnete Fenster schließen und das Programm beenden. Der scheinbare Instanzierungskonflikt durch diese zirkuläre Beziehung ist aber in Wirklichkeit gar keiner, denn bei jedem Aufruf einer der Methoden von MainFrameCommand wird an das KeyEvent-Objekt der Auslöser der Nachricht übergeben, und das ist in diesem Fall stets das MainFrameGUI-Objekt gui. So kann innerhalb des Kommando-Objekts auf alle öffentlichen Methoden des GUI-Objekts zugegriffen werden.

 Tip 

001 /* Listing1805.java */
002 
003 import java.awt.*;
004 import java.awt.event.*;
005 
006 public class Listing1805
007 {
008    public static void main(String[] args)
009    {
010       MainFrameCommand cmd = new MainFrameCommand();
011       MainFrameGUI     gui = new MainFrameGUI(cmd);
012    }
013 }
014 
015 class MainFrameGUI
016 extends Frame
017 {
018    public MainFrameGUI(KeyListener cmd)
019    {
020       super("Nachrichtentransfer");
021       setBackground(Color.lightGray);
022       setSize(300,200);
023       setLocation(200,100);
024       setVisible(true);
025       addKeyListener(cmd);
026    }
027 
028    public void paint(Graphics g)
029    {
030       g.setFont(new Font("Serif",Font.PLAIN,18));
031       g.drawString("Zum Beenden bitte ESC drücken...",10,50);
032    }
033 }
034 
035 class MainFrameCommand
036 implements KeyListener
037 {
038    public void keyPressed(KeyEvent event)
039    {
040       Frame source = (Frame)event.getSource();
041       if (event.getKeyCode() == KeyEvent.VK_ESCAPE) {
042          source.setVisible(false);
043          source.dispose();
044          System.exit(0);
045       }
046    }
047 
048    public void keyReleased(KeyEvent event)
049    {
050    }
051 
052    public void keyTyped(KeyEvent event)
053    {
054    }
055 }
Listing1805.java
Listing 18.5: Trennung von GUI- und Anwendungslogik

Diese Designvariante ist vorwiegend für größere Programme geeignet, bei denen eine Trennung von Programmlogik und Oberfläche sinnvoll ist. Für sehr kleine Programme oder solche, die wenig Ereigniscode haben, sollte eher eine der vorherigen Varianten angewendet werden, wenn diese zu aufwendig ist.

Natürlich erhebt das vorliegende Beispielprogramm nicht den Anspruch, unverändert in ein sehr großes Programm übernommen zu werden. Es soll lediglich die Möglichkeit der Trennung von Programmlogik und Oberfläche in einem großen Programm mit Hilfe der durch das Event-Handling des JDK 1.1 vorgegebenen Möglichkeiten aufzeigen. Eine sinnvolle Erweiterung dieses Konzepts könnte darin bestehen, weitere Modularisierungen vorzunehmen (z.B. analog dem MVC-Konzept von Smalltalk, bei dem GUI-Anwendungen in Model-, View- und Controller-Layer aufgesplittet werden, oder auch durch Abtrennen spezialisierter Kommandoklassen). Empfehlenswert ist in diesem Zusammenhang die Lektüre der JDK-Dokumentation, die ein ähnliches Beispiel in leicht veränderter Form enthält.

18.2.4 Variante 4: Überlagern der Event-Handler in den Komponenten

Als letzte Möglichkeit, auf Nachrichten zu reagieren, soll das Überlagern der Event-Handler in den Ereignisquellen selbst aufgezeigt werden. Jede Ereignisquelle besitzt eine Reihe von Methoden, die für das Aufbereiten und Verteilen der Nachrichten zuständig sind. Soll eine Nachricht weitergereicht werden, so wird dazu zunächst innerhalb der Nachrichtenquelle die Methode processEvent aufgerufen. Diese verteilt die Nachricht anhand ihres Typs an spezialisierte Methoden, deren Name sich nach dem Typ der zugehörigen Ereignisklasse richtet. So ist beispielsweise die Methode processActionEvent für das Handling von Action-Events und processMouseEvent für das Handling von Mouse-Events zuständig:

protected void processEvent(AWTEvent e)

protected void processComponentEvent(ComponentEvent e)

protected void processFocusEvent(FocusEvent e)

...
java.awt.Component

Beide Methodenarten können in einer abgeleiteten Klasse überlagert werden, um die zugehörigen Ereignisempfänger zu implementieren. Wichtig ist dabei, daß in der abgeleiteten Klasse die gleichnamige Methode der Basisklasse aufgerufen wird, um das Standardverhalten sicherzustellen. Wichtig ist weiterhin, daß sowohl processEvent als auch processActionEvent usw. nur aufgerufen werden, wenn der entsprechende Ereignistyp für diese Ereignisquelle aktiviert wurde. Dies passiert in folgenden Fällen:

  • Wenn ein passender Ereignisempfänger über die zugehörige addEventListener-Methode registriert wurde.
  • Wenn der Ereignistyp explizit durch Aufruf der Methode enableEvents aktiviert wurde.
 Warnung 

Die Methode enableEvents erwartet als Argument eine Maske, die durch eine bitweise Oder-Verknüpfung der passenden Maskenkonstanten aus der Klasse AWTEvent zusammengesetzt werden kann:

protected final void enableEvents(long eventsToEnable)
java.awt.Component

Die verfügbaren Masken sind analog zu den Ereignistypen benannt und heißen ACTION_EVENT_MASK, ADJUSTMENT_EVENT_MASK, COMPONENT_EVENT_MASK usw.

Das folgende Beispiel überlagert die Methode processKeyEvent in der Klasse Frame (die sie aus Component geerbt hat). Durch Aufruf von enableEvents wird die Weiterleitung der Tastaturereignisse aktiviert, und das Programm zeigt dasselbe Verhalten wie die vorigen Programme.

001 /* Listing1806.java */
002 
003 import java.awt.*;
004 import java.awt.event.*;
005 
006 public class Listing1806
007 extends Frame
008 {
009    public static void main(String[] args)
010    {
011       Listing1806 wnd = new Listing1806();
012    }
013 
014    public Listing1806()
015    {
016       super("Nachrichtentransfer");
017       setBackground(Color.lightGray);
018       setSize(300,200);
019       setLocation(200,100);
020       setVisible(true);
021       enableEvents(AWTEvent.KEY_EVENT_MASK);
022    }
023 
024    public void paint(Graphics g)
025    {
026       g.setFont(new Font("Serif",Font.PLAIN,18));
027       g.drawString("Zum Beenden bitte ESC drücken...",10,50);
028    }
029 
030    public void processKeyEvent(KeyEvent event)
031    {
032       if (event.getID() == KeyEvent.KEY_PRESSED) {
033          if (event.getKeyCode() == KeyEvent.VK_ESCAPE) {
034             setVisible(false);
035             dispose();
036             System.exit(0);
037          }
038       }
039       super.processKeyEvent(event);
040    }
041 }
Listing1806.java
Listing 18.6: Überlagern der Komponenten-Event-Handler

 Beispiel 

Diese Art der Ereignisbehandlung ist nur sinnvoll, wenn Fensterklassen oder Dialogelemente überlagert werden und ihr Aussehen oder Verhalten signifikant verändert wird. Alternativ könnte natürlich auch in diesem Fall ein EventListener implementiert und die entsprechenden Methoden im Konstruktor der abgeleiteten Klasse registriert werden.

Das hier vorgestellte Verfahren umgeht das Delegation Event Model vollständig und hat damit die gleichen inhärenten Nachteile wie das Event-Handling des alten JDK. Die Dokumentation zum JDK empfiehlt daher ausdrücklich, für alle »normalen« Anwendungsfälle das Delegation Event Model zu verwenden und die Anwendungen nach einem der in den ersten drei Beispielen genannten Entwurfsmuster zu implementieren.

 Hinweis 

18.2.5 Ausblick

Die hier vorgestellten Entwurfsmuster geben einen Überblick über die wichtigsten Designtechniken für das Event-Handling in Java-Programmen. Während die ersten beiden Beispiele für kleine bis mittelgroße Programme gut geeignet sind, kommen die Vorteile der in Variante 3 vorgestellten Trennung zwischen GUI-Code und Anwendungslogik vor allem bei größeren Programmen zum Tragen. Die vierte Variante ist vornehmlich für Spezialfälle geeignet und sollte entsprechend umsichtig eingesetzt werden.

Wir werden in den nachfolgenden Kapiteln vorwiegend die ersten beiden Varianten einsetzen. Wenn es darum geht, Ereignishandler für die Beispielprogramme zu implementieren, werden wir also entweder die erforderlichen Listener-Interfaces in der Fensterklasse selbst implementieren oder sie in lokalen oder anonymen Klassen unterbringen. Da das Event-Handling des JDK 1.1 eine Vielzahl von Designvarianten erlaubt, werden wir uns nicht immer sklavisch an die vorgestellten Entwurfsmuster halten, sondern teilweise leicht davon abweichen oder Mischformen verwenden. Dies ist beabsichtigt und soll den möglichen Formenreichtum demonstrieren. Wo nötig, werden wir auf spezielle Implementierungsdetails gesondert eingehen.

 Hinweis 

Kapitel 19 widmet sich den wichtigsten Low-Level-Events und demonstriert den genauen Einsatz ihrer Listener- und Event-Methoden anhand vieler Beispiele. In späteren Kapiteln werden die meisten der High-Level-Events erläutert. Sie werden in der Regel dort eingeführt, wo ihr Einsatz durch das korrespondierende Dialogelement motiviert wird. So erläutert Kapitel 20 in Zusammenhang mit der Vorstellung von Menüs die Action-Ereignisse, und in Kapitel 22 werden Ereignisse erläutert, die von den dort vorgestellten Dialogelementen ausgelöst werden.


 Tit   Inh   Ind   1   2   3   4   5   6   7   8   9   10   11   12   13   14   15   16   17   18   19   20   21   22   23   24   25   26   27   28   29   30   31   32   <<   <   >   >> 
Go To Java 2, Addison Wesley, Version 1.0.2, © 1999 Guido Krüger, http://www.gkrueger.com