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

Inhaltsverzeichnis
Vorwort
1 Java ist auch eine Sprache
2 Sprachbeschreibung
3 Klassen und Objekte
4 Der Umgang mit Zeichenketten
5 Mathematisches
6 Eigene Klassen schreiben
7 Angewandte Objektorientierung
8 Exceptions
9 Generics, innere Klassen
10 Die Klassenbibliothek
11 Threads und nebenläufige Programmierung
12 Datenstrukturen und Algorithmen
13 Raum und Zeit
14 Dateien und Datenströme
15 Die eXtensible Markup Language (XML)
16 Grafische Oberflächen mit Swing
17 Grafikprogrammierung
18 Netzwerkprogrammierung
19 Verteilte Programmierung mit RMI und Web–Services
20 JavaServer Pages und Servlets
21 Applets
22 Midlets und die Java ME
23 Datenbankmanagement mit JDBC
24 Reflection und Annotationen
25 Logging und Monitoring
26 Sicherheitskonzepte
27 Java Native Interface (JNI)
28 Dienstprogramme für die Java-Umgebung
Stichwort

Download:
- ZIP, ca. 14,1 MB
Buch bestellen
Ihre Meinung?

Spacer
<< zurück
Java ist auch eine Insel (8. Auflage) von Christian Ullenboom
Programmieren mit der Java Standard Edition Version 6
Buch: Java ist auch eine Insel (8. Auflage)

Java ist auch eine Insel (8. Aufl.)
8., aktual. Auflage, geb., mit DVD
1.475 S., 49,90 Euro
Galileo Computing
ISBN 978-3-8362-1371-4
Pfeil 16 Grafische Oberflächen mit Swing
Pfeil 16.1 Das Abstract Window Toolkit und Swing
Pfeil 16.1.1 SwingSet-Demos
Pfeil 16.1.2 Abstract Window Toolkit (AWT)
Pfeil 16.1.3 Java Foundation Classes
Pfeil 16.1.4 Was Swing von AWT unterscheidet
Pfeil 16.1.5 Die Klasse Toolkit
Pfeil 16.2 Fenster unter grafischen Oberflächen
Pfeil 16.2.1 Swing-Fenster darstellen
Pfeil 16.2.2 Fenster schließbar machen – setDefaultCloseOperation()
Pfeil 16.2.3 AWT-Fenster darstellen
Pfeil 16.2.4 Sichtbarkeit des Fensters
Pfeil 16.2.5 Größe und Position des Fensters verändern
Pfeil 16.2.6 Unterklassen der Fenster-Klassen bilden
Pfeil 16.2.7 Fenster- und Dialog-Dekoration, Transparenz
Pfeil 16.2.8 Dynamisches Layout während einer Größenänderung
Pfeil 16.3 Beschriftungen (JLabel)
Pfeil 16.3.1 Mehrzeiliger Text, HTML in der Darstellung
Pfeil 16.4 Icon und ImageIcon für Bilder auf Swing-Komponenten
Pfeil 16.5 Es tut sich was – Ereignisse beim AWT
Pfeil 16.5.1 Die Klasse AWTEvent
Pfeil 16.5.2 Events auf verschiedenen Ebenen
Pfeil 16.5.3 Swings Ereignisquellen und Horcher (Listener)
Pfeil 16.5.4 Listener implementieren
Pfeil 16.5.5 Listener bei dem Ereignisauslöser anmelden/abmelden
Pfeil 16.5.6 Aufrufen der Listener im AWT-Event-Thread
Pfeil 16.5.7 Adapterklassen nutzen
Pfeil 16.5.8 Innere Mitgliedsklassen und innere anonyme Klassen
Pfeil 16.6 Schaltflächen
Pfeil 16.6.1 Normale Schaltflächen (JButton)
Pfeil 16.6.2 Der aufmerksame ActionListener
Pfeil 16.6.3 Basisklasse AbstractButton
Pfeil 16.6.4 Wechselknopf (JToggleButton)
Pfeil 16.7 Swing Action
Pfeil 16.8 JComponent und Component als Basis aller Komponenten
Pfeil 16.8.1 Tooltips
Pfeil 16.8.2 Rahmen (Border)
Pfeil 16.8.3 Fokus und Navigation
Pfeil 16.8.4 Ereignisse jeder Komponente
Pfeil 16.8.5 Die Größe und Position einer Komponente
Pfeil 16.8.6 Komponenten-Ereignisse
Pfeil 16.8.7 Hinzufügen von Komponenten
Pfeil 16.8.8 UI-Delegate – der wahre Zeichner
Pfeil 16.8.9 Undurchsichtige (opake) Komponente
Pfeil 16.8.10 Properties und Listener für Änderungen
Pfeil 16.9 Container
Pfeil 16.9.1 Standardcontainer (JPanel)
Pfeil 16.9.2 Bereich mit automatischen Rollbalken (JScrollPane)
Pfeil 16.9.3 Reiter (JTabbedPane)
Pfeil 16.9.4 Teilungs-Komponente (JSplitPane)
Pfeil 16.10 Alles Auslegungssache: die Layoutmanager
Pfeil 16.10.1 Übersicht über Layoutmanager
Pfeil 16.10.2 Zuweisen eines Layoutmanagers
Pfeil 16.10.3 Im Fluss mit FlowLayout
Pfeil 16.10.4 Mit BorderLayout in allen Himmelsrichtungen
Pfeil 16.10.5 Rasteranordnung mit GridLayout
Pfeil 16.10.6 Der GridBagLayout-Manager
Pfeil 16.10.7 Null-Layout
Pfeil 16.10.8 BoxLayout
Pfeil 16.10.9 Weitere Layoutmanager
Pfeil 16.11 Rollbalken und Schieberegler
Pfeil 16.11.1 Schieberegler (JSlider)
Pfeil 16.11.2 Rollbalken (JScrollBar)
Pfeil 16.12 Kontrollfelder, Optionsfelder, Kontrollfeldgruppen
Pfeil 16.12.1 Kontrollfelder (JCheckBox)
Pfeil 16.12.2 ItemSelectable, ItemListener und das ItemEvent
Pfeil 16.12.3 Sich gegenseitig ausschließende Optionen (JRadioButton)
Pfeil 16.13 Fortschritte bei Operationen überwachen
Pfeil 16.13.1 Fortschrittsbalken (JProgressBar)
Pfeil 16.13.2 Dialog mit Fortschrittsanzeige (ProgressMonitor)
Pfeil 16.14 Menüs und Symbolleisten
Pfeil 16.14.1 Die Menüleisten und die Einträge
Pfeil 16.14.2 Menüeinträge definieren
Pfeil 16.14.3 Einträge durch Action-Objekte beschreiben
Pfeil 16.14.4 Mit der Tastatur: Mnemonics und Shortcut
Pfeil 16.14.5 Der Tastatur-Shortcut (Accelerator)
Pfeil 16.14.6 Tastenkürzel (Mnemonics)
Pfeil 16.14.7 Symbolleisten alias Toolbars
Pfeil 16.14.8 Popup-Menüs
Pfeil 16.14.9 System-Tray nutzen
Pfeil 16.15 Das Model-View-Controller-Konzept
Pfeil 16.16 Auswahlmenüs, Listen und Spinner
Pfeil 16.16.1 Auswahlmenü (JComboBox)
Pfeil 16.16.2 Zuordnung einer Taste mit einem Eintrag
Pfeil 16.16.3 Datumsauswahl
Pfeil 16.16.4 Listen (JList)
Pfeil 16.16.5 Drehfeld (JSpinner)
Pfeil 16.17 Texteingabefelder
Pfeil 16.17.1 Text in einer Eingabezeile
Pfeil 16.17.2 Die Oberklasse der Text-Komponenten (JTextComponent)
Pfeil 16.17.3 Geschützte Eingaben (JPasswordField)
Pfeil 16.17.4 Validierende Eingabefelder (JFormattedTextField)
Pfeil 16.17.5 Einfache mehrzeilige Textfelder (JTextArea)
Pfeil 16.17.6 Editor-Klasse (JEditorPane)
Pfeil 16.18 Tabellen (JTable)
Pfeil 16.18.1 Ein eigenes Tabellen-Model
Pfeil 16.18.2 Basisklasse für eigene Modelle (AbstractTableModel)
Pfeil 16.18.3 Vorgefertigtes Standard-Modell (DefaultTableModel)
Pfeil 16.18.4 Ein eigener Renderer für Tabellen
Pfeil 16.18.5 Zell-Editoren
Pfeil 16.18.6 Größe und Umrandung der Zellen
Pfeil 16.18.7 Spalteninformationen
Pfeil 16.18.8 Tabellenkopf von Swing-Tabellen
Pfeil 16.18.9 Selektionen einer Tabelle
Pfeil 16.18.10 Automatisches Sortieren und Filtern mit RowSorter
Pfeil 16.19 Bäume (JTree)
Pfeil 16.19.1 JTree und sein TreeModel und TreeNode
Pfeil 16.19.2 Selektionen bemerken
Pfeil 16.19.3 Das TreeModel von JTree
Pfeil 16.20 JRootPane und JDesktopPane
Pfeil 16.20.1 Wurzelkomponente der Top-Level-Komponenten (JRootPane)
Pfeil 16.20.2 JDesktopPane und die Kinder JInternalFrame
Pfeil 16.21 Dialoge und Window-Objekte
Pfeil 16.21.1 JWindow und JDialog
Pfeil 16.21.2 Modal oder nicht-modal
Pfeil 16.21.3 Standarddialoge mit JOptionPane
Pfeil 16.21.4 Der Dateiauswahldialog
Pfeil 16.22 Flexibles Java-Look-and-Feel
Pfeil 16.22.1 Look and Feel global setzen
Pfeil 16.22.2 UIManager
Pfeil 16.22.3 Windowsoptik mit JGoodies Looks verbessern
Pfeil 16.23 Die Zwischenablage (Clipboard)
Pfeil 16.23.1 Clipboard-Objekte
Pfeil 16.23.2 Auf den Inhalt zugreifen mit Transferable
Pfeil 16.23.3 DataFlavor ist das Format der Daten in der Zwischenablage
Pfeil 16.23.4 Einfügungen in der Zwischenablage erkennen
Pfeil 16.23.5 Drag
Pfeil 16.24 Undo durchführen
Pfeil 16.25 AWT, Swing und die Threads
Pfeil 16.25.1 Ereignisschlange (EventQueue) und AWT-Event-Thread
Pfeil 16.25.2 Swing ist nicht Thread-sicher
Pfeil 16.25.3 invokeLater() und invokeAndWait()
Pfeil 16.25.4 SwingWorker
Pfeil 16.25.5 Eigene Ereignisse in die Queue setzen
Pfeil 16.25.6 Auf alle Ereignisse hören
Pfeil 16.26 Barrierefreiheit mit der Java Accessibility API
Pfeil 16.27 Zeitliches Ausführen mit dem javax.swing.Timer
Pfeil 16.28 Alternativen zu AWT und Swing
Pfeil 16.28.1 XML-Beschreibungen der Oberfläche: Swixml, XUL/Luxor
Pfeil 16.28.2 SWT (Standard Widget Toolkit)
Pfeil 16.29 Zum Weiterlesen


Galileo Computing - Zum Seitenanfang

16.5 Es tut sich was – Ereignisse beim AWT Zur nächsten ÜberschriftZur vorigen Überschrift

Beim Arbeiten mit grafischen Oberflächen interagiert der Benutzer mit Komponenten. Er bewegt die Maus im Fenster, klickt eine Schaltfläche an oder verschiebt einen Rollbalken. Das grafische System beobachtet die Aktionen des Benutzers und informiert die Applikation über die anfallenden Ereignisse. Dann kann das laufende Programm entsprechend reagieren.


Galileo Computing - Zum Seitenanfang

16.5.1 Die Klasse AWTEvent Zur nächsten ÜberschriftZur vorigen Überschrift

Die ausgesandten Botschaften werden in Ereignis-Klassen kategorisiert. Da es unterschiedliche Ereignisse (engl. events) gibt, kann das System somit die Ereignisse unterteilen und eine Vorauswahl treffen.

Alle Ereignisse der grafischen Oberfläche sind Objekte, die aus einer Unterklasse von AWTEvent gebildet sind. Die Klasse AWTEvent ist abstrakt und selbst von EventObject aus dem util-Paket abgeleitet. Obwohl sich die meisten Oberflächen-Ereignis-Klassen in dem Unterpaket java.awt.event befinden, ist AWTEvent selbst direkt unter java.awt und damit nicht im Ereignis-Paket.

AWTEvent und Unterklassen (wie WindowEvent, KeyEvent)

Eine wichtige Methode ist getID(). Jede Ereignis-Klasse definiert eine ID, durch die sich die Ereignisse neben ihrer Klassenzugehörigkeit unterscheiden. Für Ereignisse von gedrückten Schaltflächen ist die ID etwa ActionEvent.ACTION_PERFORMED.

Natürlich stellt sich die Frage, wieso eine ID für die Ereignisse notwendig sein soll, weil die Vererbungsbeziehung doch den Typ klärt. Das ist zwar korrekt, doch gäbe es für mehr als dreißig Events zu viele Klassen. Daher haben die Entwickler ähnliche Ereignisse zu Gruppen zusammengefasst. So etwa bei einem WindowEvent, das dann versandt wird, wenn etwa das Fenster geschlossen oder verkleinert wird. In diesem Fall gibt es ein Ereignis vom Typ Win-dowEvent, aber zwei unterschiedliche IDs. So wird eine unübersehbare Anzahl von Event-Klassen vermieden. Einige Klassen verwalten weitere Konstanten, etwa für die gedrückten Tasten. Es wäre kaum sinnvoll, für jede Taste eine eigene Klasse zu schreiben. Statt einer neuen Klasse wird der Typ als eigenes Attribut im KeyEvent gespeichert.


Galileo Computing - Zum Seitenanfang

16.5.2 Events auf verschiedenen Ebenen Zur nächsten ÜberschriftZur vorigen Überschrift

Bei den Ereignissen werden zwei Typen unterschieden: die Ereignisse auf niedriger und die auf hoher Ebene.

  • Ereignisse auf niedriger Ebene (engl. low-level events). Damit sind Ereignisse auf der Ebene des grafischen Betriebssystems gemeint. Das sind etwa eine Mausbewegung oder ein Fokus auf Komponenten, Tastendrücke oder das Schließen oder Vergrößern eines Fensters.
  • Ereignisse auf höherer Ebene, semantische Ereignisse (engl. high-level events). Auf der anderen Seite gibt es Ereignisse, die von GUI-Komponenten erzeugt werden, wenn etwa eine Schaltfläche aktiviert (etwa durch Mausklick oder Drücken der Return-Taste) oder ein Rollbalken bewegt wird (zum Beispiel durch die Maus oder durch die Bild mit Pfeil nach oben-Taste). Die Swing-Komponenten reagieren meistens auf Ereignisse niedriger Ebene und formulieren daraus ein semantisches Ereignis. Es ist selten nötig, auf niedrige Ereignisse zu hören.

Die Trennung fällt aber nicht weiter auf, sodass wir im Folgenden darauf nicht eingehen werden.

Da alle grafischen Komponenten von der Klasse Component abgeleitet sind, liefern sie automatisch eine Reihe von nicht semantischen Ereignissen. Wir finden die Unterklassen und die Ereignistypen in der folgenden Tabelle.


Tabelle 16.1 Ereignisklassen und ihre IDs

Klasse ID

ComponentEvent

COMPONENT_MOVED, COMPONENT_RESIZED, COMPONENT_SHOWN, COMPONENT_HIDDEN

FocusEvent

FOCUS_GAINED, FOCUS_LOST

KeyEvent

KEY_PRESSED, KEY_RELEASED, KEY_TYPED

MouseEvent

MOUSE_CLICKED, MOUSE_DRAGGED, MOUSE_ENTERED, MOUSE_EXITED, MOUSE_MOVED, MOUSE_PRESSED, MOUSE_RELEASED

HierarchyEvent

ANCESTOR_MOVED, ANCESTOR_RESIZED, DISPLAYABILITY_CHANGED, HIERARCHY_CHANGED, PARENT_CHANGED SHOWING_CHANGED

InputMethodEvent

CARET_POSITION_CHANGED, INPUT_METHOD_TEXT_CHANGED


Weitere Ereignisse auf niedriger Ebene werden von Fenstern und Dialogen ausgelöst; sie senden Ereignisobjekte vom Typ WindowEvent. Wir werden uns in diesem Kapitel auch mit den unterschiedlichen Komponenten beschäftigen und immer gleich die zugehörigen Ereignisse untersuchen. Die folgende Tabelle zeigt für einige grafische Komponenten die Ereignisse und gibt an, wann sie ausgelöst werden können.


Tabelle 16.2 Einige Ereignisauslöser

Auslöser Wann das Event ausgelöst wird Ereignis

JButton

Aktivierung der Schaltfläche

ActionEvent

JScrollBar

Wertänderung

AdjustmentEvent

JTextComponent

Verschiebung des Cursors

CaretEvent

JSlider

Änderung der Werte

ChangeEvent

Component

Änderung der Sichtbarkeit oder Größe

ComponentEvent

Container

Änderung des Inhalts

ContainerEvent

JComponent

Neuer Fokus (bei Tastatureingaben)

FocusEvent

JEditorPane

Hyperlink-Auswahl

HyperlinkEvent

JList

Auswahl

ItemEvent

JComponent

Tastatur

KeyEvent

JMenu

Menüauswahl

MenuEvent

JComponent

Betreten oder Verlassen einer Komponente

MouseEvent

JComponent

Bewegung

MouseMotionEvent

JWindow

Zustandsänderung

WindowEvent

Eye

Augenzwinkern [Frauen zwinkern doppelt so häufig wie Männer.]

EyelidEvent



Galileo Computing - Zum Seitenanfang

16.5.3 Swings Ereignisquellen und Horcher (Listener) Zur nächsten ÜberschriftZur vorigen Überschrift

Im Ereignismodell von Java gibt es eine Reihe von Ereignisauslösern (Ereignisquellen, engl. event source), wie zum Beispiel Schaltflächen. Die Ereignisse können von der grafischen Oberfläche kommen, etwa wenn der Benutzer eine Schaltfläche anklickt, aber auch auf eigene Auslöser zurückzuführen sein. Es gibt eine Reihe von Interessenten, die gern informiert werden wollen, wenn ein Ereignis aufgetreten ist. Da der Interessent in der Regel nicht an allen ausgelösten Oberflächen-Ereignissen interessiert ist, sagt er einfach, welche Ereignisse er empfangen möchte. Dies funktioniert so, dass er sich bei einer Ereignisquelle anmeldet, und diese informiert ihn, wenn sie ein Ereignis aussendet. [Das ist so, als ob ich einer Frau, die ich gerade kennengelernt habe, meine Telefonnummer hinterlasse. Anstatt sie ewig anzurufen, warte ich. Wenn sie Interesse hat, wird sie sich melden.] Auf diese Weise leidet die Systemeffizienz nicht, da nur diejenigen informiert werden, die auch Verwendung für das Ereignis haben.

Da der Interessent an der Quelle horcht, heißt er auch Listener oder Horcher. Für jedes Ereignis gibt es einen eigenen Listener, an den das Ereignis weitergeleitet wird – darum der Name für das Modell: Delegation Model. (Die Entwickler hatten vorher den Namen »Command Model« vergeben, doch drückte dies die Arbeitsweise nicht richtig aus.) Die folgende Tabelle gibt eine Übersicht über einige Listener und was sie für Ereignisse melden.


Listener Ereignisse

ActionListener

Der Benutzer aktiviert eine Schaltfläche bzw. ein Menü oder drückt Return auf einem Textfeld.

WindowListener

Der Benutzer schließt ein Fenster oder möchte es verkleinern.

MouseListener

Druck auf einen Mausknopf

MouseMotionListener

Bewegung der Maus


Dem Listener übergibt das Grafiksystem jeweils ein Ereignis-Objekt, also dem ActionListener ein ActionEvent-Objekt, dem WindowListener ein WindowEvent-Objekt usw. Die Einzigen, die etwas aus der Reihe tanzen, sind MouseListener und MouseMotionListener, denn beide melden MouseEvent-Objekte.


Galileo Computing - Zum Seitenanfang

16.5.4 Listener implementieren Zur nächsten ÜberschriftZur vorigen Überschrift

Der Listener selbst ist eine Schnittstelle, die von den Interessenten implementiert wird. Da die Ereignis-Schnittstelle Callback-Methoden vorschreibt, muss der Interessent diese Operation implementieren. Wird im nächsten Schritt ein Horcher mit dem Ereignisauslöser verbunden, kann die Ereignisquelle davon ausgehen, dass der Horcher die entsprechende Methode besitzt. Diese ruft die Ereignisquelle bei einem Ereignis später auf.

Eine Klasse implementiert die Schnittstelle WindowListener

Um ein Fenster korrekt zu schließen, ist das WindowListener-Interface zu implementieren. Dafür bieten sich zwei Möglichkeiten:

  • Eine Klasse, die zum Beispiel JFrame erweitert, implementiert gleichzeitig WindowListener.
  • Eine ganz neue Klasse implementiert die Listener-Schnittstelle.

Während der zweite Fall im Allgemeinen der bessere ist, hat die erste Variante den Vorteil, dass der Listener leicht auf Zustände oder Variablen zugreifen kann.

Wir wollen im folgenden Beispiel unser Hauptprogramm, die Schnittstelle WindowListener, implementieren lassen.

Listing 16.6 com/tutego/insel/ui/event/CloseWindowImplementsAll.java

package com.tutego.insel.ui.event; 
 
import javax.swing.*; 
import java.awt.event.*; 
 
public class CloseWindowImplementsAll extends JFrame implements WindowListener 
{ 
  // Implement WindowListener 
 
  @Override public void windowClosing( WindowEvent event ) 
  { 
   System.exit( 0 ); 
  } 
 
  @Override public void windowClosed( WindowEvent event ) { /*Empty*/ } 
  @Override public void windowDeiconified( WindowEvent event ) { /*Empty*/ } 
  @Override public void windowIconified( WindowEvent event ) { /*Empty*/ } 
  @Override public void windowActivated( WindowEvent event ) { /*Empty*/ } 
  @Override public void windowDeactivated( WindowEvent event ) { /*Empty*/ } 
  @Override public void windowOpened( WindowEvent event ) { /*Empty*/ } 
 
  // 
 
  public CloseWindowImplementsAll() 
  { 
    setSize( 400, 400 ); 
    addWindowListener( this ); 
    setVisible( true ); 
  } 
 
  public static void main( String[] args ) 
  { 
    new CloseWindowImplementsAll(); 
  } 
}

An diesem Beispiel ist abzulesen, dass jeder, der ein WindowListener sein möchte, die vorgeschriebene Methode implementieren muss. Damit zeigt er Interesse an dem WindowEvent. Bis auf windowClosing() haben wir die anderen Operationen nicht implementiert, da sie uns nicht interessieren. Die Implementierung ist so, dass die Anwendung beendet wird, wenn der Anwender auf das x klickt.


interface java.awt.event.WindowListener 
extends EventListener

  • void windowOpened( WindowEvent e )
    Wird aufgerufen, wenn das Fenster geöffnet wurde.
  • void windowClosing( WindowEvent e )
    Wird aufgerufen, wenn das Fenster geschlossen wird.
  • void windowClosed( WindowEvent e )
    Wird aufgerufen, wenn das Fenster mit dispose() geschlossen wurde.
  • void windowIconified( WindowEvent e )
    Wird aufgerufen, wenn das Fenster zum Icon verkleinert wird.
  • void windowDeiconified( WindowEvent e )
    Wird aufgerufen, wenn das Fenster wieder hochgeholt wird.
  • void windowActivated( WindowEvent e )
    Wird aufgerufen, wenn das Fenster aktiviert wird.
  • void windowDeactivated( WindowEvent e )
    Wird aufgerufen, wenn das Fenster deaktiviert wird.

Galileo Computing - Zum Seitenanfang

16.5.5 Listener bei dem Ereignisauslöser anmelden/abmelden Zur nächsten ÜberschriftZur vorigen Überschrift

Hat der Listener die Schnittstelle implementiert, wird er mit dem Ereignisauslöser verbunden. Dafür gibt es eine Reihe von Hinzufügen- und Entfernen-Methoden, die einer Namenskonvention folgen.

  • addEreignisListener( EreignisListener )
  • removeEreignisListener( EreignisListener )

Dies bedeutet, dass etwa ein Listener für Fenster-Ereignisse, ein WindowListener, der WindowEvent-Ereignisse auslöst, mit der Methode addWindowListener() an das Fenster gebunden wird. Üblicherweise lassen sich beliebig viele Listener an einen Ereignisauslöser hängen.

Listing 16.7 CloseWindowImplementsAll.java, CloseWindowImplementsAll()

  CloseWindowImplementsAll() 
  { 
    setSize( 400, 400 ); 
    addWindowListener( this ); 
    setVisible( true ); 
  }

Wir tragen mit addWindowListener() den Listener (bei this das eigene Objekt als Listener) in eine interne Liste ein. Immer wenn ein Event ausgelöst wird, kümmert sich die jeweilige Methode um dessen Abarbeitung.

Natürlich kann nicht jede Komponente jedes Ereignis auslösen. Daher gibt es nur Hinzufügemethoden für Ereignisse, die die Komponenten tatsächlich auslösen. Ein Fenster wird zum Beispiel kein ActionEvent auslösen, daher fehlt ihm eine Methode addActionListener(). Dafür kann ein Fenster Fenster-Ereignisse auslösen und besitzt eine Methode addWindowListener(). Eine Schaltfläche wiederum löst keine Fenster-Ereignisse aus, und daher gibt es die Methode addWindowListener() bei Schaltflächen nicht. So lassen sich über die angebotenen addXXXListener()-Methoden gut die Ereignisse ablesen, die eine Komponente auslösen kann, denn das XXX wird dann nach der Namenskonvention der Ereignis-Typ sein.


Galileo Computing - Zum Seitenanfang

16.5.6 Aufrufen der Listener im AWT-Event-Thread Zur nächsten ÜberschriftZur vorigen Überschrift

Nachdem der Listener implementiert und angemeldet wurde, ist das System im Fall eines aufkommenden Ereignisses bereit, es zu verteilen. Aktiviert zum Beispiel der Benutzer eine Schaltfläche, so führt der AWT-Event-Thread – auch Event-Dispatching-Thread genannt – den Programmcode im Listener selbstständig aus. Sehr wichtig ist Folgendes: Der Programmcode im Listener sollte nicht zu lange dauern, da sich sonst Ereignisse in der Queue sammeln, die der AWT-Thread nicht mehr verarbeiten kann. Diese Eigenschaft fällt dann schnell auf, wenn sich Aufforderungen zum Neuzeigen (Repaint-Ereignisse) aufstauen, da auf diese Weise leicht ein »stehendes System« entsteht.

Die Reihenfolge, in der die Listener abgearbeitet werden, ist im Prinzip undefiniert. Zwar reiht sie Sun in ihrer Implementierung in eine Liste ein, sodass es dadurch eine Reihenfolge gibt, doch sollte es keine Beachtung dieses Implementierungsdetails geben.


Galileo Computing - Zum Seitenanfang

16.5.7 Adapterklassen nutzen Zur nächsten ÜberschriftZur vorigen Überschrift

Der Nachteil der ersten Variante besteht darin, dass wir immer alle Methoden implementieren müssen, auch wenn wir nur eine der vielen Methoden benötigen. Hier helfen Adapterklassen – Klassen, die die Schnittstellen mit leeren Rümpfen implementieren. Hat beispielsweise die Schnittstelle WindowListener sieben Methoden, so steht in der Adapterklasse folgende Implementierung:

Listing 16.8 java.awt.event.WindowAdapter

public abstract class WindowAdapter 
  implements WindowListener, WindowStateListener, WindowFocusListener 
{ 
    public void windowOpened( WindowEvent e ) { } 
    public void windowClosing( WindowEvent e ) { } 
    public void windowClosed( WindowEvent e ) { } 
    public void windowIconified( WindowEvent e ) { } 
    public void windowDeiconified( WindowEvent e ) { } 
    public void windowActivated( WindowEvent e ) { } 
    public void windowDeactivated( WindowEvent e ) { } 
    public void windowStateChanged( WindowEvent e ) { } 
    public void windowGainedFocus( WindowEvent e ) { } 
    public void windowLostFocus( WindowEvent e ) { } 
}

Zusätzlich entdecken wir einige Methoden, die nicht direkt von unserem WindowListener stammen, sondern von zwei weiteren Schnittstellen, die jetzt keine Rolle spielen.

Wenn wir jetzt einen Ereignisbehandler verwenden, erweitern wir einfach die Adapterklasse. Unser Programm zum Schließen des Fensters mit einer externen Adapterklasse sieht dann wie folgt aus:

Listing 16.9 com/tutego/insel/ui/event/CloseWindowWithAdapter.java

package com.tutego.insel.ui.event; 
 
import java.awt.event.*; 
import javax.swing.*; 
 
public class CloseWindowWithAdapter 
{ 
  public static void main( String[] args ) 
  { 
    JFrame f = new JFrame(); 
    f.setSize( 400, 400 ); 
    f.setVisible( true ); 
 
    f.addWindowListener( new CloseWindowAction() ); 
  } 
} 
 
class CloseWindowAction extends WindowAdapter 
{ 
  @Override 
  public void windowClosing( WindowEvent e ) { System.exit(0); } 
}

Der Unterschied zwischen windowClosing() und windowClosed()

Die Schnittstelle WindowListener schreibt zwei Methoden vor, deren Namen sich ziemlich ähnlich anhören: windowClosing() und windowClosed(). Betrachten wir den Unterschied zwischen beiden und wie ein Programm beide Methoden nutzen oder meiden kann.

In den einfachen Programmen setzen wir in die windowClosing()-Methode einen Aufruf von System.exit(), um die Applikation zu beenden, da windowClosing() immer bei Beendigung der Applikation mit dem ´ am Fenster aufgerufen wird. Was allerdings leicht vergessen wird, ist die Tatsache, dass nicht nur der Benutzer über das ´ das Fenster schließen kann, sondern auch die Applikation über die spezielle Methode dispose(). Sie gibt alle Ressourcen frei und schließt das Fenster. Die Applikation ist dann allerdings noch nicht beendet. Damit wir das Schließen mit dem ´ und durch dispose() unterscheiden können, kümmert sich windowClosing() um das ´ und windowClosed() um das dispose(). Wenn wir lediglich mit dem ´ das Fenster schließen und die Applikation beendet werden soll, muss nicht noch extra dispose() schön brav die Ressourcen freigeben. Daher reicht oft ein System.exit(). Soll das Fenster jedoch mit ´ und dispose() einfach nur geschlossen werden oder ist eine gemeinsame Behandlung gewünscht, ist es sinnvoll, in windowClosing() mit dispose() indirekt window-Closed() aufzurufen. Das sieht dann folgendermaßen aus:

class WL extends WindowAdapter 
{ 
  public void windowClosing( WindowEvent e ) 
  { 
    event.getWindow().dispose(); 
  } 
  public void windowClosed( WindowEvent e ) 
  { 
    // Das Fenster ist geschlossen, und jetzt können wir hier 
    // weitermachen, etwa mit System.exit(), wenn alles 
    // vorbei sein soll. 
  } 
}

setDefaultCloseOperation() und der WindowListener

Die Anweisung setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE) ist eigentlich nur zu Testzwecken nützlich, denn in ausgewachsenen GUI-Anwendungen sollte sich die Applikation nicht einfach schließen, sondern mit einem Dialog über das Ende informieren. Hier werden nun die Konstanten HIDE_ON_CLOSE und DISPOSE_ON_CLOSE für die setDefaultCloseOperation() interessant. Sie kennzeichnen zum einen, ob das Fenster automatisch verdeckt werden soll, nachdem die WindowListener aufgerufen wurden (dies ist der Standard), und zum anderen, ob alle Listener abgearbeitet werden sollen und das Fenster geschlossen werden soll. HIDE_ON_CLOSE ist die Standardeinstellung.


Galileo Computing - Zum Seitenanfang

16.5.8 Innere Mitgliedsklassen und innere anonyme Klassen topZur vorigen Überschrift

Wir haben für die Adapterklasse eine externe Klasse benutzt, weil das Erweitern wegen der Einfachvererbung schnell an seine Grenzen stößt. Mit inneren Klassen wird allerdings alles elegant, denn sie können leicht auf Zustände der äußeren Klasse zugreifen. Dabei lassen sich innere Klassen auf unterschiedliche Weise verwenden. Zum einen als Mitgliedsklasse; das heißt, die Klasse, die bisher als externe Klasse vorgelegen hat, wird in eine andere Klasse hineingenommen. Im vorigen Beispiel bedeutet dies: Wir nehmen CloseWindowAction in die Klasse CloseWindowWithAdapter auf und schreiben die Klassendeklaration nicht unter der anderen Klasse. Zum anderen kann die innere Klasse wie eine lokale Variablendeklaration noch in die Methode aufgenommen werden, die die addXXXListener()-Methode beinhaltet.

Der zweite Weg führt über innere anonyme Klassen. Dadurch wird das Programm zwar schön kurz, doch lange Ereignisbehandler führen schnell zu unübersichtlichem Quellcode. Implementieren wir unser Programm zum Schließen des Fensters mit einer inneren anonymen Klasse:

Listing 16.10 com/tutego/insel/ui/event/CloseWindowWithInnerClass.java

package com.tutego.insel.ui.event; 
 
import java.awt.event.*; 
import javax.swing.*; 
 
public class CloseWindowWithInnerClass extends JFrame 
{ 
  public CloseWindowWithInnerClass() 
  { 
    setSize( 400, 400 ); 
 
    addWindowListener( new WindowAdapter() { 
      @Override public void windowClosing( WindowEvent e ) { 
        System.exit( 0 ); 
      } 
    } ); 
  } 
 
  public static void main( String[] args ) 
  { 
    new CloseWindowWithInnerClass().setVisible( true ); 
  } 
}

Die Lösung hat den Vorteil, dass nicht extra eine eigene Klasse mit einem häufig überflüssigen Namen angelegt wird. Die Unterklasse von WindowAdapter ist nur hier sinnvoll und wird nur in diesem Kontext benötigt.



Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.






<< zurück
  Zum Katalog
Zum Katalog: Java ist auch eine Insel





Java ist auch eine Insel
Jetzt bestellen


 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Tipp
Zum Katalog: Coding for Fun





 Coding for Fun


 Buchempfehlungen
Zum Katalog: Objektorientierte Programmierung





 Objektorientierte
 Programmierung


Zum Katalog: Einstieg in Eclipse 3.4






 Einstieg in
 Eclipse 3.4


Zum Katalog: Java 6 lernen mit Eclipse






 Java 6 lernen
 mit Eclipse


Zum Katalog: NetBeans Platform 6






 NetBeans
 Platform 6


Zum Katalog: Java und XML






 Java und XML


Zum Katalog: Visual C# 2008






 Visual C# 2008


Zum Katalog: IT-Handbuch für Fachinformatiker






 IT-Handbuch für
 Fachinformatiker


Zum Katalog: C++ von A bis Z






 C++ von A bis Z


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo




Copyright © Galileo Press 2009
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, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de