7.4 Programmskelette für ein einfaches Hauptfenster

Klasse Fenster
/* * Fenster.java */ package at.beringer.oopBuch.guiSwing; import javax.swing.JFrame; /** Applikation für einfachstes Fenster der Klasse 'JFrame'. <hr /> @since Mai 2000 @version Jänner 2002 (Swing ab JDK 1.3) @version <br />Dezember 2004 (deprecated-Methode 'show' von Window-Klasse ersetzt) @see Fenster1 @see Fenster2 @author Beringer Alfred */ public class Fenster { // ------------------------------------------------------------------------- // Klassenmethode 'main' // ------------------------------------------------------------------------- /** Der Einstiegspunkt für die Anwendung. @param args Kommandozeilenparameter */ public static void main(String[ ] args) { JFrame rahmen = new JFrame(); // Fensterinstanz erzeugen rahmen.setTitle("Swing-Fenster - Titelzeile"); // Text für Titelzeile rahmen.setSize(480, 260); // Fenstergröße definieren // Achtung: Standardgröße = (0,0)! rahmen.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Definition für Standardoperation seit JDK 1.3 möglich // Achtung: Fenster wird standardmäßig nicht geschlossen! rahmen.setVisible(true); // Fenster anzeigen und nach vorne bringen } }


Im Allg. leitet man das Hauptfenster einer Applikation von der Klasse JFrame ab:

Klasse Fenster1
/* * Fenster1.java */ package at.beringer.oopBuch.guiSwing; import javax.swing.JFrame; /** Einfachstes Hauptfenster ohne Ereigniswächter (Variante 1). <hr /> @since Mai 2000 @version Jänner 2002 (Swing ab JDK 1.3) @version <br />Dezember 2004 (deprecated-Methode 'show' von Window-Klasse ersetzt) @see Fenster @see Fenster2 @author Beringer Alfred */ public class Fenster1 extends JFrame { // ------------------------------------------------------------------------- // Klassenmethode 'main' // ------------------------------------------------------------------------- /** Der Einstiegspunkt für die Anwendung. @param args Kommandozeilenparameter */ public static void main(String[ ] args) { JFrame rahmen = new Fenster1(); // Fensterinstanz erzeugen rahmen.setVisible(true); // Fenster anzeigen und nach vorne bringen } // ------------------------------------------------------------------------- // Konstruktoren // ------------------------------------------------------------------------- /** Standardkonstruktor */ public Fenster1() { this.setTitle("Swing-Fenster1 - Titelzeile"); // Text für Titelzeile this.setSize(480, 260); // Fenstergröße definieren this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Definition für Standardoperation seit JDK 1.3 möglich } }


Der Konstruktor kann auch leer sein (die Nachrichten setTitle und setSize werden an die Fensterinstanz gesendet - siehe 1. Programmversion) oder alles erfolgt im Konstruktor:

Klasse Fenster2
/* * Fenster2.java */ package at.beringer.oopBuch.guiSwing; import javax.swing.JFrame; /** Einfachstes Hauptfenster ohne Ereigniswächter (Variante 2). <hr /> @since Mai 2000 @version Jänner 2002 (Swing ab JDK 1.3) @version <br />Dezember 2004 (deprecated-Methode 'show' von Window-Klasse ersetzt) @see Fenster @see Fenster1 @author Beringer Alfred */ public class Fenster2 extends JFrame { // ------------------------------------------------------------------------- // Klassenmethode 'main' // ------------------------------------------------------------------------- /** Der Einstiegspunkt für die Anwendung. @param args Kommandozeilenparameter */ public static void main(String[ ] args) { new Fenster2("Swing-Fenster2 - Titelzeile"); // Fensterinstanz erzeugen } // ------------------------------------------------------------------------- // Konstruktoren // ------------------------------------------------------------------------- /** Konstruktor mit Parameter für Titelzeilentext. @param titel Titelzeilentext */ public Fenster2(String titel) { super(titel); // Text für Titelzeile (mit einem JFrame-Konstruktor) this.setSize(480, 260); // Fenstergröße definieren this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Definition für Standardoperation seit JDK 1.3 möglich this.setVisible(true); // Fenster anzeigen und nach vorne bringen } }


Alle 3 Applikationen erzeugen das gleiche Standardfenster (abgesehen vom unterschiedlichen Text in der Titelzeile), das bereits die vollständige Funktionalität eines Windows-Fensters besitzt.
Klassendefinition und Hauptprogramm (= Anwendungsprogramm) sind allerdings nicht getrennt!

7.4.1 Klassendefinition für Hauptfenster (Swing JDK 1.2, AWT ab JDK 1.1)

Die Methode setDefaultCloseOperation gibt es für Swing-Fenster (JFrame) erst seit dem JDK 1.3. Für AWT-Fenster (Frame) gibt es keine solche Methode. Entfernt man aus den vorhergehenden Programmen die entsprechenden Zeilen, läßt sich keines dieser Fenster standardmäßig schließen! Die solcherart entstehenden Programme lassen sich dann nur mehr durch Abbrechen (d.h. durch Drücken von 'Strg' + 'C' ) beenden.

Die folgenden Klassendefinitionen zeigen das Prinzip der Ereignisverarbeitung in Java (ab JDK 1.1) am Beispiel eines sogenannten Ereigniswächters zum Schließen eines Fensters (davor können eventuell noch Aktionen durchgeführt werden).

7.4.1.1 Klasse für GUI-Code (Fenster)

Klasse Hauptfenster1A
/* * Hauptfenster1A.java */ package at.beringer.oopBuch.guiSwing; import javax.swing.*; /** Einfaches Hauptfenster mit unabhängigem Ereigniswächter A. <p> Controller-Klasse: 'FensterWaechterA' </p> <hr /> @since Mai 2000 @version Jänner 2002 (Swing JDK 1.2) @see FensterWaechterA @see ProgrammHauptfenster1A @see Hauptfenster1B @see Hauptfenster2 @see Hauptfenster3 @author Beringer Alfred */ public class Hauptfenster1A extends JFrame { // ------------------------------------------------------------------------- // Konstruktoren // ------------------------------------------------------------------------- /** Standardkonstruktor */ public Hauptfenster1A() { this.setTitle("Swing-Hauptfenster1A - unabhängige Klasse"); this.setSize(480, 260); this.addWindowListener(new FensterWaechterA()); // anmelden beim Ereigniswächter } }


7.4.1.2 Klasse für Anwendungscode (Ereigniswächter)

Klasse FensterWaechterA
/* * FensterWaechterA.java */ package at.beringer.oopBuch.guiSwing; import javax.swing.*; import java.awt.event.*; /** Ereigniswächter für Ereignis "Fenster schließen" - Variante A ('getSource'). <hr /> @since Mai 2000 @version Jänner 2002 (Swing JDK 1.2) @see Hauptfenster1A @see ProgrammHauptfenster1A @see FensterWaechterB @author Beringer Alfred */ public class FensterWaechterA extends WindowAdapter { // ------------------------------------------------------------------------- // API-Methoden überschreiben // ------------------------------------------------------------------------- /** API-Methode für Schließen des Fensters */ @Override public void windowClosing(WindowEvent evt) { schliessenFenster(evt); // Ereignisobjekt mitgeben, falls Daten vom Ereignis benötigt werden } // ************************************************************************* // Ereignisbehandlungsmethoden // ************************************************************************* /** Methode für "Fenster schließen". @param evt WindowEvent (von API-Methode 'windowClosing' übernommen) */ private void schliessenFenster(WindowEvent evt) { /* 'getSource()' liefert Ereignisquelle als 'Object'-Instanz Bem.: Ereignisquelle = jene GUI-Komponente, die ein Ereignis (z.B. "Fenster schließen") ausgelöst hat */ JFrame fenster = (JFrame) evt.getSource(); // ... Aktionen vor Schließen des Fensters JOptionPane.showMessageDialog(fenster, "Das Fenster wird geschlossen"); fenster.setVisible(false); fenster.dispose(); System.exit(0); // Programm beenden } }


Das Fenster will auf das Ereignis "Fenster Schließen" reagieren. Dieses Ereignis ist ein Fenster-Ereignis ("Window-Event"). Es genügt aber nicht, nur die API-Methode "windowClosing" zu implementieren, das Fenster muss sich auch bei einem Ereigniswächter bzw. Ereignisbearbeiter für Fenster-Ereignisse - einem sogenannten Event-Listener bzw. Event-Adapter - anmelden. Im Ereigniswächter ist die gewünschte Methode implementiert, d.h. im Ereigniswächter erfolgt die gewünschte Reaktion auf das Ereignis - d.h. weiters, im Wächter steckt die eigentliche Verarbeitung. Die Anmeldung erfolgt mit Hilfe der Methode addXXListener, wobei 'XX' für die Art des Ereignisses steht.

Für verschiedene Ereignisse gibt es verschiedene Listener bzw. Adapter. Da das Ereignis "Fenster Schließen" ein Window-Event ist, muss sich das Fenster bei einem Window-Listener bzw. Window-Adapter anmelden - mittels der Methode addWindowListener. Ein Listener ist eine Schnittstelle (interface - siehe Kap.5.4), während ein Adapter eine Klasse ist, in der alle (abstrakten) Listener-Methoden als leere Methoden implementiert sind. Leitet man eine Klasse von einem Listener ab, müssen alle Methoden implementiert werden - auch jene, die man eigentlich gar nicht benötigt. Leitet man eine Klasse jedoch von einem Adapter ab, müssen nur jene Methoden implementiert werden, die man wirklich braucht.

Der Anwendungscode (= Verarbeitungscode - reagieren auf Ereignisse) sollte immer vom GUI-Code (= Fenster konstruieren und initialisieren) getrennt werden - wie oben gezeigt, geschieht dies durch Kapselung in voneinander unabhängige Klassen.

Erfolgt diese Trennung jedoch nicht, könnte die eigene Fensterklasse als Event-Listener angemeldet werden (mittels addXXListener(this) ). In diesem Fall werden die entsprechenden Methoden in der Fensterklasse selbst implementiert. Allerdings kann man die eigene Fensterklasse - die von der Klasse JFrame abgeleitet ist - nicht auch noch von einer Event-Adapter-Klasse ableiten, sondern nur mehr von einem Event-Listener-Interface (Einfachvererbung!). Daher müsste man in diesem Fall alle Listener-Methoden implementieren - die nicht benötigten durch leere Methoden. Diese Vorgangsweise ist aber ein sehr schlechter Programmierstil!

In Java kann als Ereigniswächter eine lokale Klasse ("inner class") oder eine sog. anonyme Klasse definiert werden:

7.4.1.3 Klassendefinition mit lokaler (innerer) Klasse

Klasse Hauptfenster2
/* * Hauptfenster2.java */ package at.beringer.oopBuch.guiSwing; import javax.swing.*; import java.awt.event.*; /** Einfaches Hauptfenster mit lokalem Ereigniswächter. <p> Lokale Klasse: 'FensterWaechter' </p> <hr /> @since Mai 2000 @version Jänner 2002 (Swing JDK 1.2) @see ProgrammHauptfenster2 @see Hauptfenster1A @see Hauptfenster1B @see Hauptfenster3 @author Beringer Alfred */ public class Hauptfenster2 extends JFrame { // ------------------------------------------------------------------------- // Konstruktoren // ------------------------------------------------------------------------- /** Standardkonstruktor */ public Hauptfenster2() { this.setTitle("Swing-Hauptfenster2 - lokale (innere) Klasse"); this.setSize(480, 260); this.addWindowListener(new FensterWaechter()); // anmelden beim Ereigniswächter } // ************************************************************************* // Lokale (innere) Klasse // ************************************************************************* /** Ereigniswächter. */ class FensterWaechter extends WindowAdapter { // --------------------------------------------------------------------- // API-Methoden überschreiben // --------------------------------------------------------------------- /** API-Methode für Schließen des Fensters */ @Override public void windowClosing(WindowEvent evt) { schliessenFenster(evt); // Ereignisobjekt mitgeben, falls Daten vom Ereignis benötigt werden } // --------------------------------------------------------------------- // Ereignisbehandlungsmethoden // --------------------------------------------------------------------- /** Methode für "Fenster schließen". @param evt WindowEvent (von API-Methode 'windowClosing' übernommen) */ private void schliessenFenster(WindowEvent evt) { /* 'getWindow()' liefert zugeordnetes Fenster (= Ereignisquelle, die das Ereignis "Fenster schließen" ausgelöst hat) als 'Window'-Instanz */ JFrame fenster = (JFrame) evt.getWindow(); // ... Aktionen vor Schließen des Fensters JOptionPane.showMessageDialog(fenster, "Das Fenster wird geschlossen"); fenster.setVisible(false); fenster.dispose(); System.exit(0); // Programm beenden } } // ********************************************* Ende lokale (innere) Klasse } // Ende der Klassendefinition


7.4.1.4 Klassendefinition mit anonymer (innerer) Klasse

Klasse Hauptfenster3
/* * Hauptfenster3.java */ package at.beringer.oopBuch.guiSwing; import javax.swing.*; import java.awt.event.*; /** Einfaches Hauptfenster mit anonymem Ereigniswächter. <p> Anonyme Klasse: von 'WindowAdapter' </p> <hr /> @since Mai 2000 @version Jänner 2002 (Swing JDK 1.2) @see ProgrammHauptfenster3 @see Hauptfenster2 @see Hauptfenster1A @see Hauptfenster1B @author Beringer Alfred */ public class Hauptfenster3 extends JFrame { // ------------------------------------------------------------------------- // Konstruktoren // ------------------------------------------------------------------------- /** Standardkonstruktor */ public Hauptfenster3() { this.setTitle("Swing-Hauptfenster3 - anonyme Klasse"); this.setSize(480, 260); // anmelden beim Ereigniswächter mit gleichzeitiger Klassendefinition: this.addWindowListener( new WindowAdapter() // *************************************************************** // anonyme (innere) Klasse // *************************************************************** { // ----------------------------------------------------------- // API-Methoden überschreiben // ----------------------------------------------------------- /** API-Methode für Schließen des Fensters */ @Override public void windowClosing(WindowEvent evt) { schliessenFenster(evt); // Ereignisobjekt mitgeben, // falls Daten vom Ereignis benötigt werden } } // ********************************** Ende anonyme (innere) Klasse ); } // ************************************************************************* // Ereignisbehandlungsmethoden (private Methoden des Hauptfensters) // ************************************************************************* /** Methode für "Fenster schließen". @param evt WindowEvent (von API-Methode 'windowClosing' übernommen) */ private void schliessenFenster(WindowEvent evt) { // ... Aktionen vor Schließen des Fensters JOptionPane.showMessageDialog(this, "Das Fenster wird geschlossen"); this.setVisible(false); this.dispose(); System.exit(0); // Programm beenden } } // Ende der Klassendefinition


7.4.2 Hauptprogramm für eine GUI-Applikation

Das Hauptprogramm für eine GUI-Applikation sollte immer eine eigene Klasse sein - eine Applikationsklasse mit der Klassenmethode main. Die einfachste Applikationsklasse sieht daher folgendermaßen aus:

Programmklasse ProgrammGUI
/* * ProgrammGUI.java */ package at.beringer.oopBuch.guiSwing; public class ProgrammGUI { public static void main(String[] args) { // Fensterinstanz erzeugen: javax.swing.JFrame rahmen = new Hauptfenster(); // Fenster anzeigen: rahmen.setVisible(true); } }


Nachdem das Fenster angezeigt wurde, wird die Methode main beendet, die Swing-Applikation allerdings läuft weiter! Aus diesem Grund sollte die Swing-Applikation immer in einem eigenen Thread (siehe Kap.5.15) laufen. Dieser Thread wird "Event Dispatch Thread" (kurz EDT) genannt. Eine Applikationsklasse sollte daher immer folgendermaßen aussehen (nähere Hinweise zum EDT und der verwendeten Klasse SwingUtilities findet man in der Java-Dokumentation):

Programmklasse ProgrammGUI
/* * ProgrammGUI.java */ package at.beringer.oopBuch.guiSwing; public class ProgrammGUI { public static void main(String[] args) { javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { javax.swing.JFrame rahmen = new Hauptfenster(); rahmen.setVisible(true); } }); } }


Standardmäßig wird die "Look-and-Feel"-Oberfläche von Java ("CrossPlatform" - auch "Metal" oder "Ocean" genannt) verwendet. Möchte man jedoch die "Look-and-Feel"-Oberfläche des zugrundeliegenden Systems berücksichtigen, dann kann die folgende Applikationsklasse verwendet werden:

Programmklasse ProgrammGUI
/* * ProgrammGUI.java */ package at.beringer.oopBuch.guiSwing; import javax.swing.JFrame; import javax.swing.SwingUtilities; import javax.swing.UIManager; public class ProgrammGUI { public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { try { UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName()); } catch (Exception exc) { System.err.println("System-LnF nicht gefunden"); } JFrame rahmen = new Hauptfenster(); rahmen.setVisible(true); } }); } }



Weiter
zu den Java-GUI-Beispielen von Kapitel 7.5 (Fenster mit Label und Buttons)
zu den Java-GUI-Beispielen von Kapitel 7.8 (Maus, Musterfenster, Menü)
zu den Java-GUI-Beispielen von Kapitel 7.9 (I18N - L10N - Parametrisierung)
zu den Java-GUI-Beispielen von Kapitel 7.10 (Dialogfenster)
zu Kapitel 8 (JDBC)
zu den C#-Klassenbeispielen von Kapitel 9.19.1 (Exceptions)
zu den C#-Klassenbeispielen von Kapitel 10 (Ein-/Ausgabe von Daten)
zu Kapitel 12 (PL/I)
zu Kapitel 13 (Reservierte Worte)
Zurück
zum Anfang dieses Kapitels
zum Inhaltsverzeichnis
 
zu Kapitel 1
zu den Klassenbeispielen von Kapitel 2
zur Parameterübergabe (Kapitel 2.7.1)
zu Kapitel 3
zu den Klassenbeispielen von Kapitel 4
zu den Java-Klassenbeispielen von Kapitel 5.19.1 (Exceptions)
zu den Java-Klassenbeispielen von Kapitel 6 (Ein-/Ausgabe von Daten)
Zur
Java-Dokumentation der Java-Beispiele