Interfaces
Die Methode closeWindow() ist gut geeignet, durch Beenden der Laufzeitumgebung das Fenster zu schließen. Allerdings wäre es netter, wenn dies nicht automatisch nach einer bestimmten Zeitgeschähe, sondern dann, wenn der Nutzer das Fenster auch schliessen will. In Java benutzt man in solchen Fällen einen Listener. Listener werden von dafür vorbereiteten Klassen aufgerufen, wenn ein bestimmtes Ereignis eintritt. ClosableFrame hat beispielsweise eine Methode:
public void addWindowListener(java.awt.event.WindowListener);
die über “java.awt.Frame“ von „java.awt.Window“ geerbt wurde. Wenn wir also einen solchen WindowListener an ClosableFrame hängten, würden wir mitbekommen, wann Benutzereingaben erfolgen, die den Fensterstatus verändern sollen, und könnten entsprechend reagieren. Was also ist ein WindowListener?
Tja, blöd, WindowListener ist keine Klasse sondern ein Interface. Was ist das? Wenn eine Klasse der Bauplan für ein Objekt ist, dann ist ein Interface ein Vertrag überzugesicherten Eigenschaften eines Objekts, die der Bauplan realisieren muss. Ein Interface enthält keine Programmierung und lässt sich nicht instanzieren; es deklariert lediglich einige Methoden, die beispielsweise ein Objekt, das für einen WindowListener durchgehen will, anbieten muss. Um ein Interface zu verwenden, müssen wir eine Klasse programmieren, die das Interface implementiert. Wir können sogar viele Klassen programmieren, die für einen WindowListener durchgehen würden. Das ist auch der Sinn eines Interfaces: Ganz unterschiedliche Klassen können eine einheitliche Schnittstelle anbieten, indem sie ein bestimmtes Interface implementieren. So kann man beispielsweise ganz unterschiedliche Datenbanken mitdem selben Java-Code nutzen, wenn die jeweiligen Datenbanktreiber alle das Interface „java.sql.Connection“ implementieren.
Hier ist das Originalinterface WindowListener, das sich die Programmierer von Sun Microsystems ausgedacht haben. Wie Sie sehen, besteht es überwiegend aus Kommentaren. Die Methoden sind nur deklariert, aber nicht ausprogrammiert; die geschweiften Klammernfehlen bereits.
/*
* @(#)WindowListener.java 1.18 01/12/03
*
* Copyright 2002 Sun Microsystems, Inc. All rights reserved.
* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
package java.awt.event;
import java.util.EventListener;
/**
* The listener interface for receiving window events.
* The class that is interested in processing a window event
* either implements this interface (and all the methods it
* contains) or extends the abstract WindowAdapter class
* (overriding only the methods of interest).
* The listener object created from that class is then registered with a
* Window using the window's addWindowListener
* method. When the window's status changes by virtue of being opened,
* closed, activated or deactivated, iconified or deiconified,
* the relevant method in the listener object is invoked, and the
* WindowEvent is passed to it.
*
* @author Carl Quinn
* @version 1.18, 12/03/01
*
* @see WindowAdapter
* @see WindowEvent
* @see Tutorial: Writing a Window Listener
* @see Reference: The Java Class Libraries (update file)
*
* @since 1.1
*/
public interface WindowListener extends EventListener {
/**
* Invoked the first time a window is made visible.
*/
public void windowOpened(WindowEvent e);
/**
* Invoked when the user attempts to close the window
* from the window's system menu. If the program does not
* explicitly hide or dispose the window while processing
* this event, the window close operation will be cancelled.
*/
public void windowClosing(WindowEvent e);
/**
* Invoked when a window has been closed as the result
* of calling dispose on the window.
*/
public void windowClosed(WindowEvent e);
/**
* Invoked when a window is changed from a normal to a
* minimized state. For many platforms, a minimized window
* is displayed as the icon specified in the window's
* iconImage property.
* @see java.awt.Frame#setIconImage
*/
public void windowIconified(WindowEvent e);
/**
* Invoked when a window is changed from a minimized
* to a normal state.
*/
public void windowDeiconified(WindowEvent e);
/**
* Invoked when the Window is set to be the active Window. Only a Frame or
* a Dialog can be the active Window. The native windowing system may
* denote the active Window or its children with special decorations, such
* as a highlighted title bar. The active Window is always either the
* focused Window, or the first Frame or Dialog that is an owner of the
* focused Window.
*/
public void windowActivated(WindowEvent e);
/**
* Invoked when a Window is no longer the active Window. Only a Frame or a
* Dialog can be the active Window. The native windowing system may denote
* the active Window or its children with special decorations, such as a
* highlighted title bar. The active Window is always either the focused
* Window, or the first Frame or Dialog that is an owner of the focused
* Window.
*/
public void windowDeactivated(WindowEvent e);
}
Man sieht, dass das ganz normaler Java-Code ist, wie wir ihn auchschreiben können.
public interfaceWindowListener extends EventListener
Ein Interface wird mit dem Schlüsselwort „interface“ definiert. Wie Sie erkennen, kann auch ein Interface ein anderes Interface erweitern, von ihm erben. Alle Methoden sind nur als Rumpf vorhanden, bereits die geschweiften Klammern fehlen. Ein Interface kann daneben Konstanten definieren.
Zurück zu unserem Problem. Wir müssen nun eine Klasse schreiben, die dieses Interface implementiert, das heißt die entsprechenden Methoden ausprogrammiert und mit Leben füllt.
Zusätzlich müssen wir der Laufzeitumgebung mitteilen, dass diese zu schreibende Klasse ein WindowListener sein soll. Das geschiehtdurch das Schlüsselwort implements. Diese Klasse können wir dann instanzieren und als WindowListener an addWindowListener(..) übergeben. Eine solche Klasse sieht beispielsweise so aus:
Wir müssen alle Methoden, die das Interface WindowListener vorschreibt, ausprogrammieren, auch wenn es teilweise nur leere Methoden sind. Anderenfalls würde unser Objekt nicht für einen WindowListener durchgehen können. Der Unterschied zwischendem Interface und der implementierenden Klasse ist also teilweise lediglich, dass statt der Methodensignatur:
public voidwindowDeactivated(WindowEvent e);
eine leere Methode angegeben wird:
public voidwindowDeactivated(WindowEvent e) { }
Den ExitVMWindowListener verknüpfen wir mit unserem ClosableFrame durch die Methode „addWindowListener“, die java.awt.Frame (von java.awt.Window geerbt) anbietet:
Wenn der Benutzer das Fenster schliessen will, wird die entsprechende Methode („public void windowClosing(WindowEvent e)“) von der Laufzeitumgebung aufgerufen und unser Code kommt zur Aktion. Die gewünschte Funktionalität ist da!
Aufgabe: CloseableFrame5
Eigentlich könnte ClosableFrame das WindowListener Interfaceauch selbst implementieren. Es gibt jedenfalls keinen Grund, hier eine eigene Klasse zu verwenden. Also:
Schreiben Sie eine Klasse ClosableFrame5, die selbstWindowListener implementiert und sich selbst als WindowListener aufruft. Die Klasse soll eine main−Methode besitzen und ausführbar sein.
Hinweis: Erinnern Sie sich, dass das aktuelle Objekt mit dem "this"−Operator referenziert wird.
Musterlösung: java1.aufg.kap_2.ClosableFrame5