From 33613a85afc4b1481367fbe92a17ee59c240250b Mon Sep 17 00:00:00 2001
From: Sven Eisenhauer
+Die Klasse JFrame
+ist die wichtigste Hauptfensterklasse in Swing. Sie ist aus java.awt.Frame
+abgeleitet und stellt ein Hauptfenster mit Rahmen, Systemmenü
+und Standardschaltflächen zur Verfügung. Ein JFrame
+kann ebenso einfach instanziert werden wie ein Frame:
+
+
+Der parameterlose Konstruktor erzeugt ein Hauptfenster mit einer leeren
+Titelzeile, der andere schreibt den übergebenen String hinein.
+Da JFrame
+aus Frame
+abgeleitet ist, stehen alle Methoden aus Window,
+Container
+und Component
+zur Verfügung. Ein einfaches Beispielprogramm mit einem leeren
+Hauptfenster, das sich über den Schließen-Button beenden
+läßt, können wir (analog zu den Beispielen in Kapitel 31)
+wie folgt realisieren:
+
+
+
+
+
+
+ Titel
+ Inhalt
+ Suchen
+ Index
+ DOC
+ Handbuch der Java-Programmierung, 5. Auflage
+
+ <<
+ <
+ >
+ >>
+ API
+ Kapitel 36 - Swing: Container und Menüs
+
+
+
+
+
+36.1 Hauptfenster
+
+
+
+
+
+
+
+
+36.1.1 JFrame
+
+
+
+
+
+
+
+
+
+
+public JFrame()
+public JFrame(String title)
+
+
+
+javax.swing.JFrame
+
+
+
+Listing 36.1: Verwendung der Klasse JFrame
+
+
+
+
+
+001 /* Listing3601.java */
+002
+003 import javax.swing.*;
+004 import java.awt.event.*;
+005
+006 public class Listing3601
+007 extends JFrame
+008 {
+009 public Listing3601()
+010 {
+011 super("Ein einfacher JFrame");
+012 addWindowListener(new WindowClosingAdapter(true));
+013 }
+014
+015 public static void main(String[] args)
+016 {
+017 Listing3601 wnd = new Listing3601();
+018 wnd.setLocation(100, 100);
+019 wnd.setSize(300, 200);
+020 wnd.setVisible(true);
+021 }
+022 }
+
+
+Listing3601.java
+
+Das Programm erzeugt ein Hauptfenster der Größe 300 * 200 +an der Bildschirmposition (100, 100). In der Titelzeile steht »Ein +einfacher JFrame«, und das Programm läßt sich durch +einen Klick auf den Schließen-Button beenden: +
+ +
+Abbildung 36.1: Ein einfaches JFrame-Beispiel
+ + + + ++Ein bedeutender Unterschied zwischen den AWT- und Swing-Hauptfenstern +besteht in ihrer Komponentenstruktur und den sich daraus ergebenden +Unterschieden in der Bedienung. Während die Komponenten eines +AWT-Fensters direkt auf dem Fenster platziert werden, besitzt ein +Swing-Hauptfenster eine einzige Hauptkomponente, die alle anderen +Komponenten aufnimmt. + +
+Diese Hauptkomponente wird als RootPane +bezeichnet und ist vom Typ JRootPane. +Sie übernimmt die Rolle einer Art Verwaltungsinstanz für +alle anderen Komponenten des Hauptfensters. Eine RootPane enthält +folgende Komponenten: +
+Die LayeredPane enthält ihrerseits zwei Unterkomponenten: +
+Damit ergibt sich folgende Struktur: +
+ +
+Abbildung 36.2: Die Struktur einer RootPane
+ ++LayeredPane und GlassPane liegen »übereinander« und +füllen das Fenster jeweils komplett aus. Die GlassPane ist normalerweise +durchsichtig und wird meist nicht zur Grafikausgabe benutzt. Sie könnte +dann verwendet werden, wenn Effekte erzielt werden sollen, die das +Fenster als Ganzes betreffen (und nicht seine einzelnen Dialogelemente). +Eine (beispielsweise von JInternalFrame +genutzte) Funktion besteht darin, Mausereignisse abzufangen, bevor +sie an andere Komponenten weitergegeben werden. + +
+Die LayeredPane enthält das Menü und die Dialogelemente +der Anwendung. Als Instanz der Klasse JLayeredPane +verfügt sie über die Fähigkeit, Dialogelemente nicht +nur neben-, sondern in kontrollierter Weise auch übereinander +anzuordnen. Das ist beispielsweise wichtig, um Menüs oder interne +Dialoge über den Komponenten anzuzeigen, die sie verdecken. Tatsächlich +verdeckt das in der LayeredPane gehaltene Menü die in seiner +ContentPane platzierten Dialogelemente der Anwendung. + +
+Das hört sich alles sehr kompliziert an, und mancher wird sich +fragen, ob soviel Aufwand wirklich nötig war. Glücklicherweise +braucht eine Swing-Anwendung sich um die Details gar nicht zu kümmern. +Einerseits wird die RootPane, und mit ihr die darin enthaltene GlassPane, +LayeredPane und ContentPane, beim Anlegen des Fensters automatisch +erzeugt (einzig die Menüleiste bleibt standardmäßig +leer). Zweitens implementieren alle Hauptfenster das Interface RootPaneContainer, +das den Zugriff auf die RootPane vereinfacht. Einige seiner Methoden +sind: + +
+
+
++public JRootPane getRootPane() +public Container getContentPane() +public JLayeredPane getLayeredPane() +public Component getGlassPane() ++ + |
++javax.swing.RootPaneContainer | +
+Um auf einem Hauptfenster Komponenten zu platzieren, ist es also nicht +nötig, zunächst mit getRootPane +die RootPane, dann mit getLayeredPane +die LayeredPane und schließlich mit getContentPane +die ContentPane zu beschaffen, sondern es kann direkt getContentPane +aufgerufen werden. Neben den getter-Methoden gibt es auch setter-Methoden, +mit denen der strukturelle Aufbau der RootPane vollständig verändert +werden kann. Darauf wollen wir aber nicht weiter eingehen. + + + + +
+Das Einfügen und Anordnen von Dialogelementen auf einem Hauptfenster +erfolgt also über dessen ContentPane. Die Aufrufe von add +und setLayout +werden damit nicht direkt auf dem Fenster ausgeführt, sondern +auf dessen ContentPane, die über einen Aufruf von getContentPane +beschafft werden kann. + +
+Um das zu demonstrieren, wollen wir das vorige Beispiel um drei Buttons +erweitern, die mit Hilfe eines GridLayout +der Größe 3 * 1 angeordnet werden: + + +
+
+
+
+001 /* Listing3602.java */
+002
+003 import javax.swing.*;
+004 import java.awt.*;
+005 import java.awt.event.*;
+006
+007 public class Listing3602
+008 extends JFrame
+009 {
+010 public Listing3602()
+011 {
+012 super("Ein einfacher JFrame");
+013 //WindowListener hinzufügen
+014 addWindowListener(new WindowClosingAdapter(true));
+015 //Layout setzen und Buttons hinzufügen
+016 Container contentPane = getContentPane();
+017 contentPane.setLayout(new GridLayout(3, 1));
+018 contentPane.add(new JButton("Button 1"));
+019 contentPane.add(new JButton("Button 2"));
+020 contentPane.add(new JButton("Button 3"));
+021 }
+022
+023 public static void main(String[] args)
+024 {
+025 Listing3602 wnd = new Listing3602();
+026 wnd.setLocation(100, 100);
+027 wnd.setSize(300, 200);
+028 wnd.setVisible(true);
+029 }
+030 }
+
+ |
++Listing3602.java | +
+Das Programm hat nun folgendes Aussehen: +
+ +
+Abbildung 36.3: Ein Hauptfenster mit Dialogelementen
++
![]() |
+![]() |
+
+
+ +Gerade am Anfang passiert es mitunter, dass add +oder setLayout +versehentlich direkt aus dem Hauptfenster aufgerufen werden. Um das +zu verhindern, besitzen die Hauptfensterklassen einen Mechanismus, +der in einem solchen Fall eine Ausnahme mit einem entsprechenden Warnhinweis +auslöst. Dieser kann zwar mit der Methode setRootPaneCheckingEnabled +deaktiviert werden, normalerweise ist das aber nicht zu empfehlen. |
+
+
|
+![]() |
+
+Die zweite Hauptfensterklasse, die wir in diesem Kapitel vorstellen, +ist JWindow. +Sie ist aus Window +abgeleitet und dient wie diese dazu, ein rahmenloses Fenster zu erzeugen, +das an beliebiger Stelle und in beliebiger Größe auf dem +Bildschirm platziert werden kann. JWindow +besitzt drei Konstruktoren: +
+
+
++public JWindow() +public JWindow(Frame owner) +public JWindow(Window owner) ++ + |
++javax.swing.JWindow | +
+Ebenso wie JFrame +besitzt auch JWindow +eine RootPane mit der im vorigen Abschnitt beschriebenen Struktur. +Dialogelemente und Layoutmanager werden also nicht direkt auf dem +Fenster, sondern auf der ContentPane platziert. Zur einfacheren Verwendung +implementiert auch JWindow +das Interface RootPaneContainer. + +
+Als Beispiel für die Anwendung von JWindow +wollen wir einen einfachen SplashScreen +konstruieren, also ein Fenster, das nach dem Start eines Programms +angezeigt wird und nach dessen Initialisierung wieder entfernt wird. +Dazu leiten wir eine Klasse SplashScreen +von JWindow +ab und platzieren darin ein Icon und einen Text. Der Name der Icondatei +und der Text können an den Konstruktor übergeben werden. +Das Programm soll jeweils ein Drittel der verfügbaren Höhe +und Breite des Bildschirms belegen und das Icon und den Text zentriert +darin anzeigen. + + +
+
+
+
+001 /* SplashScreen.java */
+002
+003 import javax.swing.*;
+004 import javax.swing.border.*;
+005 import java.awt.*;
+006 import java.awt.event.*;
+007
+008 public class SplashScreen
+009 extends JWindow
+010 {
+011 public SplashScreen(String image, String text)
+012 {
+013 JPanel contentPane = new JPanel();
+014 contentPane.setLayout(new BorderLayout());
+015 Border bd1 = BorderFactory.createBevelBorder(
+016 BevelBorder.RAISED
+017 );
+018 Border bd2 = BorderFactory.createEtchedBorder();
+019 Border bd3 = BorderFactory.createCompoundBorder(bd1, bd2);
+020 ((JPanel)contentPane).setBorder(bd3);
+021 ImageIcon icon = new ImageIcon(image);
+022 contentPane.add(new JLabel(" ", JLabel.CENTER), BorderLayout.NORTH);
+023 contentPane.add(new JLabel(icon, JLabel.CENTER), BorderLayout.CENTER);
+024 contentPane.add(new JLabel(text, JLabel.CENTER), BorderLayout.SOUTH);
+025 setContentPane(contentPane);
+026 }
+027
+028 public void showFor(int millis)
+029 {
+030 Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
+031 setLocation(dim.width / 3, dim.height / 3);
+032 setSize(dim.width / 3, dim.height / 3);
+033 setVisible(true);
+034 try {
+035 Thread.sleep(millis);
+036 } catch (InterruptedException e) {
+037 }
+038 setVisible(false);
+039 }
+040
+041 public static void main(String[] args)
+042 {
+043 SplashScreen intro = new SplashScreen(
+044 "mine.gif",
+045 "(C) Copyright 2000, J. Krüger, All Rights Reserved"
+046 );
+047 intro.showFor(3000);
+048 System.exit(0);
+049 }
+050 }
+
+ |
++SplashScreen.java | +
+Die Ausgabe des Programms sieht so aus: +
+ +
+Abbildung 36.4: Ein einfacher SplashScreen
+ ++Das Programm ist prinzipiell so aufgebaut wie die bisherigen Swing-Beispiele, +zeigt aber bei näherem Hinsehen einige Besonderheiten. Zunächst +definiert es einen eigenen ContentPane. In Zeile 013 +wird dazu ein JPanel +instanziert und mit einem BorderLayout +versehen (der Standard-Layoutmanager von JPanel +ist FlowLayout). +Alle Dialogelemente werden auf diesem Panel platziert. In Zeile 025 +wird das Panel durch Aufruf von setContentPane +als ContentPane des Fensters definiert. + +
+Zum anderen zeigt das Programm ein paar zusätzliche Möglichkeiten, +Umrandungen zu verwenden. Ab Zeile 015 +werden mit Hilfe der Methoden createBevelBorder +und createEtchedBorder +der Klasse BorderFactory +zwei unabhängige Umrandungen konstruiert. Durch Aufruf von createCompoundBorder +werden sie zu einer neuen Umrandung zusammengefasst und anschließend +an den ContentPane übergeben. + + + + +
+Neben einem oder mehreren langlebigen Hauptfenstern besitzt eine Anwendung +meist auch Dialogfenster. Sie werden oft nur vorübergehend aufgerufen, +um eine temporäre Kommunikation zwischen Anwender und Programm +zu etablieren. Dialogfenster unterscheiden sich meist dadurch von +Hauptfenstern, dass sie kein Menü und nur eingeschränkte +Systemfunktionen besitzen. Zudem ist ihre Größe oft nicht +veränderbar, und sie halten (als modale Fenster) während +der eigenen Ausführung den Programmfluss im übrigen Programm +an. + +
+Mit der aus Dialog +abgeleiteten Klasse JDialog +stehen auch in Swing Dialogfenster zur Verfügung. Sie besitzen +denselben strukturellen Aufbau wie JFrame +und JWindow +und implementieren ebenfalls das Interface RootPaneContainer. +Auch hier erfolgt also das Hinzufügen und Anordnen von Komponenten +nicht auf dem Fenster selbst, sondern auf seiner ContentPane. JDialog +besitzt eine Vielzahl von Konstruktoren. Die wichtigsten sind: +
+
+
++public JDialog(Frame owner) +public JDialog(Frame owner, boolean modal) +public JDialog(Frame owner, String title) +public JDialog(Frame owner, String title, boolean modal) ++ + |
++javax.swing.JDialog | +
+Als owner sollte der Aufrufer +dabei das Fenster übergeben, zu dem der Dialog logisch gehört. +Alle Konstruktoren gibt es auch in einer Form, bei der der owner +vom Typ Dialog +ist. Wahlweise kann ein JDialog +auch ohne owner konstruiert +werden (mit dem parameterlosen Konstruktor), doch dann kann es unter +Umständen Fokusprobleme beim Wechsel zwischen mehreren Anwendungen +geben. + +
+Die übrigen Parameter geben den Titel des Dialogs an und legen +fest, ob er modal oder nicht-modal sein soll. Bei einem modalen Dialog +wird der Aufruf von show +(bzw. setVisible(true)) erst +dann beendet, wenn der Dialog geschlossen wurde. Bei einem nicht-modalen +Dialog fährt das Programm dagegen unmittelbar mit der nächsten +Anweisung hinter show +fort. + + + + +
+Eine weitere (und noch dazu sehr bequeme) Möglichkeit, Swing-Dialoge +zu erzeugen, steht mit der Klasse JOptionPane +zur Verfügung. Diese ist in der Lage, einfache Dialoge, die lediglich +ein Icon und einen Text oder ein Eingabefeld und eine Auswahl der +Buttons »Yes«, »No« und »Cancel« enthalten, +mit einem einzigen Aufruf einer statischen Methode zu erzeugen. JOptionPane +ist sehr vielseitig, wir wollen uns an dieser Stelle allerdings auf +ihre wichtigsten Anwendungen beschränken. + + + + +
+In seiner einfachsten Form kann JOptionPane +dazu verwendet werden, ein Dialogfenster mit Titel, Icon und Hinweistext +anzuzeigen, das mit Hilfe eines »OK«-Buttons beendet werden +kann. Dazu stehen verschiedene Varianten der Methode showMessageDialog +zur Verfügung: +
+
+
++public static void showMessageDialog( + Component parentComponent, + Object message +) + +public static void showMessageDialog( + Component parentComponent, + Object message, + String title, + int messageType +) + +public static void showMessageDialog( + Component parentComponent, + Object message, + String title, + int messageType, + Icon icon +) ++ + |
++javax.swing.JOptionPane | +
+Aufrufe von showMessageDialog +sind grundsätzlich modal. Erst wenn der Dialog vom Anwender beendet +wurde, wird die nächste Anweisung ausgeführt. Der Parameter +parentComponent bezeichnet die +Vaterkomponente, aus der heraus der Dialog aufgerufen wurde, und message +ist der anzuzeigende Text. Soll eine eigene Titelzeile angegeben werden, +kann dazu title verwendet werden, +andernfalls wird »Message« angezeigt. Wahlweise kann mit +dem Parameter icon ein Icon +angegeben werden, das neben dem Text angezeigt wird. Alternativ kann +auch durch Übergabe einer der Konstanten ERROR_MESSAGE, +INFORMATION_MESSAGE, +WARNING_MESSAGE, +QUESTION_MESSAGE +oder PLAIN_MESSAGE +an den Parameter messageType +ein Standard-Icon erzeugt werden: +
+ +
+Abbildung 36.5: Die Standard-Icons bei JOptionPane
+ + + + ++Mit den verschiedenen Varianten der Methode showConfirmDialog +kann ein Dialog erzeugt werden, der neben den zuvor besprochenen Fähigkeiten +die Möglichkeit bietet, die Auswahl der Buttons zu beeinflussen, +mit denen der Dialog beendet werden kann. +
+
+
++public static int showConfirmDialog( + Component parentComponent, + Object message +) + +public static int showConfirmDialog( + Component parentComponent, + Object message, + String title, + int optionType +) + +public static int showConfirmDialog( + Component parentComponent, + Object message, + String title, + int optionType, + int messageType +) + +public static int showConfirmDialog( + Component parentComponent, + Object message, + String title, + int optionType, + int messageType, + Icon icon +) ++ + |
++javax.swing.JOptionPane | +
+Die Parameter entsprechen im wesentlichen denen der Methode showMessageDialog. +Zusätzlich kann mit optionType +eine der Konstanten YES_NO_OPTION, +OK_CANCEL_OPTION +oder YES_NO_CANCEL_OPTION +angegeben werden, um zu entscheiden, welche Kombination von Buttons +der Dialog anzeigen soll: +
+ +
+Abbildung 36.6: Button-Kombinationen bei showConfirmDialog
+ ++showConfirmDialog +ist ebenfalls modal und ihr Rückgabewert zeigt an, auf welche +Weise der Dialog beendet wurde: + +
+
| Rückgabewert | +Bedeutung |
| YES_OPTION | +Mit dem »Yes«-Button |
| NO_OPTION | +Mit dem »No«-Button |
| CANCEL_OPTION | +Mit dem »Cancel«-Button |
| OK_OPTION | +Mit dem »OK«-Button |
| CLOSED_OPTION | +Mit dem »Schließen«-Button +der Titelzeile |
+Tabelle 36.1: Rückgabewerte von showConfirmDialog
+ + + + ++Mit der Möglichkeit, neben dem Icon und dem Nachrichtentext auch +ein Textfeld im Dialog zu platzieren, kann JOptionPane +auch zur Erfassung einfacher Daten verwendet werden. Die dazu aufzurufende +Methode showInputDialog +gibt es ebenfalls in mehreren Varianten: +
+
+
++public static String showInputDialog( + Component parentComponent, + Object message +) + +public static String showInputDialog( + Component parentComponent, + Object message, + String title, + int messageType +) + +public static Object showInputDialog( + Component parentComponent, + Object message, + String title, + int messageType, + Icon icon, + Object[] selectionValues, + Object initialSelectionValue +) ++ + |
++javax.swing.JOptionPane | +
+In der einfachsten Form werden lediglich ein Dialog mit dem Titel +»Input«, die angegebene Nachricht mit einem Icon und das +Textfeld zur Eingabe der Daten angezeigt. Die zweite Variante erlaubt +zusätzlich die Angabe der Titelzeile und die Auswahl des Icontyps. +In der letzten Variante wird anstelle des Textfelds eine Combobox +zur Dateneingabe verwendet. Der Parameter selectionValues +gibt die in der Combobox anzuzeigenden Elemente an (sie werden mit +toString +in Strings konvertiert), und initialSelectionValue +gibt an, welches von ihnen standardmäßig selektiert werden +soll. + +
+Bei allen Methoden ist der Rückgabewert ein String mit den vom +Anwender eingegebenen Daten. Falls eine Combobox zur Auswahl verwendet +wurde, wird der String-Wert des ausgewählten Elements zurückgegeben. +Ein Rückgabewert von null +zeigt an, dass der Anwender den Dialog abgebrochen hat. + +
+Das folgende Programm zeigt eine einfache Anwendung von JOptionPane, +bei der der Anwender einen Wert aus einer vordefinierten Liste auswählen +kann: + + +
+
+
+
+001 /* Listing3604.java */
+002
+003 import javax.swing.*;
+004 import java.awt.*;
+005 import java.awt.event.*;
+006
+007 public class Listing3604
+008 extends JFrame
+009 {
+010 private static final String[] QUARTALE = {
+011 "1. Quartal", "2. Quartal", "3. Quartal", "4. Quartal"
+012 };
+013
+014 public Listing3604()
+015 {
+016 super("Test von JOptionPane");
+017 addWindowListener(new WindowClosingAdapter(true));
+018 }
+019
+020 public static void main(String[] args)
+021 {
+022 Listing3604 wnd = new Listing3604();
+023 wnd.setLocation(100, 100);
+024 wnd.setSize(300, 200);
+025 wnd.setVisible(true);
+026 String ret = (String)JOptionPane.showInputDialog(
+027 wnd,
+028 "Wählen Sie das Quartal aus",
+029 "JOptionPane.showInputDialog",
+030 JOptionPane.QUESTION_MESSAGE,
+031 null,
+032 QUARTALE,
+033 QUARTALE[2]
+034 );
+035 System.out.println("Ausgewählt wurde " + ret);
+036 }
+037 }
+
+ |
++Listing3604.java | +
+Der vom Programm erzeugte Dialog sieht unmittelbar nach dem Aufruf +von showInputDialog +so aus: +
+ +
+Abbildung 36.7: Die Methode showInputDialog
+ + + + ++Die Klasse JApplet +ist eine einfache Erweiterung von java.applet.Applet. +Sie dient zur Entwicklung von Applets, die Swing-Dialogelemente zur +Gestaltung der Oberfläche verwenden. Die Unterschiede zwischen +beiden Klassen sind nicht sehr umfangreich; insbesondere werden die +Methoden init, +start, +stop +und destroy +in derselben Weise verwendet wie bei der Klasse Applet. + +
+Wie bei den anderen Hauptfenstern ist auch hier der wichtigste Unterschied, +dass JApplet +die in Abschnitt 36.1.1 +beschriebene RootPane-Struktur realisiert. Die Klasse implementiert +ebenfalls das RootPaneContainer-Interface, +und alle Komponenten müssen an die ContentPane übergeben +werden. Da die Applet-Programmierung ab Kapitel 39 +ausführlich beschrieben wird, wollen wir uns an dieser Stelle +auf ein einfaches Beispiel beschränken: + + +
+
+
+
+001 /* JAppletTest.java */
+002
+003 import javax.swing.*;
+004 import java.awt.*;
+005 import java.awt.event.*;
+006
+007 public class JAppletTest
+008 extends JApplet
+009 {
+010 public void init()
+011 {
+012 Container contentPane = getContentPane();
+013 contentPane.setLayout(new GridLayout(3, 1));
+014 contentPane.add(new JButton("Button 1"));
+015 contentPane.add(new JButton("Button 2"));
+016 contentPane.add(new JButton("Button 3"));
+017 }
+018 }
+
+ |
++JAppletTest.java | +
+Das Programm stellt ein sehr einfaches Applet dar, das - analog zu +Listing 36.2 - drei +Buttons in einem GridLayout +anzeigt. Es kann wie folgt in eine HTML-Datei eingebettet werden: + + +
+
+
++001 <html> +002 <head><title>JAppletTest</title></head> +003 +004 <body> +005 <h1>JAppletTest</h1> +006 +007 <applet code="JAppletTest.class" width=300 height=200> +008 Hier steht das JAppletTest +009 </applet> +010 +011 </body> +012 </html>+ + |
++japplet.html | +
+Das Applet kann nun mit Hilfe des AppletViewers gestartet werden:
+
+
+appletviewer japplet.html
+
+
+
+
+
+
+
+Bei vielen Programmen ist es üblich, dass sie ein einziges Hauptfenster +besitzen und ihre zahlreichen, gleichzeitig geöffneten Kindfenster +innerhalb dieses Hauptfensters anordnen. Diese unter Windows +als MDI (Multiple Document Interface) +bezeichnete Technik ist bei bestimmten Typen von Anwendungen mittlerweile +weitverbreitet (z.B. bei Textverarbeitungen, Grafikprogrammen oder +Entwicklungsumgebungen). + +
+Während im AWT keine Möglichkeit vorgesehen war, MDI-Anwendungen +zu entwickeln, ist es in Swing recht einfach. Dazu werden lediglich +zwei Arten von Komponenten benötigt: +
+Als Desktop ist prinzipiell jede beliebige Hauptfensterklasse geeignet, +meist wird aber die Klasse JFrame +verwendet. Um die Kindfenster zu verwalten, wird die vordefinierte +ContentPane durch eine Instanz der Klasse JDesktopPane +ersetzt. Diese von JLayeredPane +abgeleitete Klasse besitzt einen DesktopManager, +der für die Verwaltung der Kindfenster zuständig ist. Der +DesktopManager +wird beispielsweise benachrichtigt (und führt alle dazu erforderlichen +Aktionen aus), wenn ein Kindfenster verkleinert, vergrößert +oder verschoben werden soll. +
+
![]() |
+
+
+ +DesktopManager +ist ein Interface, das eine Vielzahl von Methoden enthält. Mit +der Klasse DefaultDesktopManager +gibt es eine Standardimplementierung, die für viele Zwecke ausreichend +ist. |
+
+
|
+![]() |
+
+Die Kindfenster werden aus JInternalFrame +abgeleitet; einem Dialogelement, das recht überzeugend vortäuscht, +ein Hauptfenster zu sein. Tatsächlich ist JInternalFrame +direkt aus JComponent +abgeleitet und nicht aus JFrame, +wie man es vielleicht vermuten könnte. Der Grund liegt darin, +dass JFrame +als Frame +stets eine betriebssystemspezifische Fensterressource besitzt und +damit für die Verwendung innerhalb der Grenzen eines anderen +Fensters ungeeignet ist. + +
+Eine betriebssystemspezifische Ressource für MDI-Kindfenster +steht aber nicht auf allen grafischen Oberflächen zur Verfügung, +und so haben sich die Swing-Entwickler entschlossen, JInternalFrame +als leichtgewichtige Komponente selbst zu realisieren. + +
+Das hat einige Konsequenzen: +
+
![]() |
+![]() |
+
+
+ +Um die Kindfenster zu aktivieren, müssen sie durch Aufruf von +setVisible +sichtbar gemacht und mit add +auf dem Desktop platziert werden. Bis zum JDK 1.2 war der Aufruf von +setVisible +nicht unbedingt erforderlich, denn ein JInternalFrame +war standardmäßig sichtbar. Zur Angleichung an die anderen +Hauptfensterklassen wurde dies mit dem JDK 1.3 geändert. |
+
+
|
+![]() |
+
+JInternalFrame +besitzt diverse Konstruktoren. Das nachfolgende Syntaxdiagramm zeigt +nur den umfangreichsten von ihnen. Alle anderen ergeben sich, indem +man auf der rechten Seite nicht benötigte Argumente wegfallen +läßt: +
+
+
++public JInternalFrame( + String title, + boolean resizable, + boolean closable, + boolean maximizable, + boolean iconifiable +) ++ + |
++javax.Swing.JInternalFrame | +
+JInternalFrame +implementiert das schon erläuterte Interface RootPaneContainer +und stellt zusätzlich verschiedene Methoden zur Verfügung. +Einige von ihnen sind: +
+
+
++public void setClosable(boolean b) +public void setResizable(boolean b) +public void setIconifiable(boolean b) +public void setMaximizable(boolean b) + +public void setTitle(String title) + +public void setDefaultCloseOperation(int operation) ++ + |
++javax.Swing.JInternalFrame | +
+setClosable +entscheidet, ob das Fenster geschlossen, und setResizable, +ob seine Größe verändert werden kann. setIconifiable +legt fest, ob das Fenster in ein Symbol verkleinert, und setMaximizable, +ob es maximiert werden kann. Mit setTitle +kann der Rahmentitel angegeben werden, und mit setDefaultCloseOperation +wird angegeben, wie das Fenster sich beim Schließen verhalten +soll. Hier kann eine der Konstanten DO_NOTHING_ON_CLOSE, +HIDE_ON_CLOSE +oder DISPOSE_ON_CLOSE +angegeben werden. + + + + +
+Nach diesen Vorbemerkungen wollen wir ein einfaches Beispielprogramm +erstellen. Es soll einen JFrame +als Desktop mit zwei Kindfenstern enthalten. Diese sollen alle Standardbedienelemente +enthalten, vergrößer- und verkleinerbar sein und innerhalb +des Desktops verschoben werden können. + +
+Wir erstellen dazu eine Klasse DesktopFrame, +die mit einem DefaultDesktopManager +ein Desktop aufbaut. Mit ihrer Methode addChild +kann ein Kindfenster an einer bestimmten Position auf dem Desktop +platziert werden. Weiterhin definieren wir eine aus JInternalFrame +abgeleitete Klasse ChildFrame. +Sie legt im Konstruktor die Eigenschaften des Fensters fest, hat darüber +hinaus aber keine Funktionalitäten. + + +
+
+
+
+001 /* Listing3607.java */
+002
+003 import java.awt.*;
+004 import java.awt.event.*;
+005 import javax.swing.*;
+006
+007 class DesktopFrame
+008 extends JFrame
+009 {
+010 private JDesktopPane desk;
+011
+012 public DesktopFrame()
+013 {
+014 super("DesktopFrame");
+015 this.desk = new JDesktopPane();
+016 desk.setDesktopManager(new DefaultDesktopManager());
+017 setContentPane(desk);
+018 addWindowListener(new WindowClosingAdapter(true));
+019 }
+020
+021 public void addChild(JInternalFrame child, int x, int y)
+022 {
+023 child.setLocation(x, y);
+024 child.setSize(200, 150);
+025 child.setDefaultCloseOperation(
+026 JInternalFrame.DISPOSE_ON_CLOSE
+027 );
+028 desk.add(child);
+029 child.setVisible(true);
+030 }
+031 }
+032
+033 class ChildFrame
+034 extends JInternalFrame
+035 {
+036 public ChildFrame(String title)
+037 {
+038 super("Child " + title, true, true);
+039 setIconifiable(true);
+040 setMaximizable(true);
+041 setBackground(Color.lightGray);
+042 }
+043 }
+044
+045 public class Listing3607
+046 {
+047 public static void main(String[] args)
+048 {
+049 //Desktop erzeugen
+050 DesktopFrame desktop = new DesktopFrame();
+051 desktop.setLocation(100, 100);
+052 desktop.setSize(400, 300);
+053 desktop.setVisible(true);
+054 //Zwei ChildFrames hinzufügen
+055 desktop.addChild(new ChildFrame("1"), 10, 10);
+056 desktop.addChild(new ChildFrame("2"), 20, 20);
+057 }
+058 }
+
+ |
++Listing3607.java | +
+Die Ausgabe des Programms sieht so aus: +
+ +
+Abbildung 36.8: Die Klasse JInternalFrame
+| Titel + | Inhalt + | Suchen + | Index + | DOC + | Handbuch der Java-Programmierung, 5. Auflage, Addison +Wesley, Version 5.0.1 + |
| << + | < + | > + | >> + | API + | © 1998, 2007 Guido Krüger & Thomas +Stark, http://www.javabuch.de + |