11 Swing & Co

Nachdem wir im vorherigen Kapitel das AWT und grundsätzlich das Eventhandling unter Java diskutiert haben, wollen wir in diesem Kapitel Swing und die neueren Oberflächentechniken von Java allgemein (JFC) ansprechen. Swing ist ein praktisches Beispiel eines Konzepts, das massiv auf dem Eventmodell 1.1 aufbaut und eine wesentliche Erweiterung des AWT-Modells darstellt. Wohlbemerkt, eine Erweiterung. Die bisherigen AWT-Techniken lassen sich in Java immer anwenden und im Prinzip auch mit Swing-Elementen mischen, was aber nicht sonderlich sinnvoll ist. Swing implementiert einen neuen Satz von GUI-Komponenten mit anpassungsfähigem Look and Feel. Swing ist vollständig in 100 % purem Java implementiert und basiert auf dem JDK 1.1 Lightweight UI Framework. Lightweight bedeutet, dass keine Peer-Klassen mehr benötigt werden. Das Aussehen und die Reaktionen von GUI-Komponenten passen sich auf Wunsch automatisch an jede unterstützte Betriebssystemplattform (Windows, Solaris, Macintosh) an. Sie schwingen - daher der Name Swing - sozusagen zwischen den verschiedenen Welten hin und her (wenn Sie es wollen). Um dies zu realisieren, gibt es in Swing den UIManager mit Methoden wie setLookAndFeel() oder getSystemLookAndFeelClassName().

Swing-Komponenten beinhalten vollständig die bisherigen AWT-Komponenten (Button, Scrollbar, Label usw.), plus einen Satz von Higher-Level-Komponenten (Baumansichten, Listboxen usw.).

Das Kapitel baut auf dem AWT-Kapitel auf und verzichtet deshalb auf einige Erklärungen, die dort bereits erfolgt sind.

11.1 Das Swing-API

Java 1.1 hat Swing das erste Mal eingeführt, aber Swing ist nicht gleich Swing. Die Swing-API-Referenz hat sich über die Entwicklung des Konzepts bis zu der Finalversion 1.2 des JDK erheblich verändert (danach ist es nur noch erweitert worden). Das gesamte API ist beim Wechsel von Java 1.1 zu Java 2 umstrukturiert und verlagert worden. Leider ist diese Umstrukturierung ziemlich chaotisch und schlecht dokumentiert erfolgt. Selbst die Beta-3-Version des JDK 1.2 hatte Swing noch so organisiert, wie es unter dem JDK 1.1 üblich war. Erst die kaum beachtete - letzte - Betaversion des JDK 1.2 veränderte dann die Struktur, was in der Entwicklerschaft zu ziemlichem Ungemach führte. Ab Java 2 befindet sich die gesamte Swing-Funktionalität in dem Hauptpaket javax. Swing besteht aus folgenden Paketen:

javax.swing 
javax.swing.border 
javax.swing.colorchooser 
javax.swing.event 
javax.swing.filechooser 
javax.swing.plaf 
javax.swing.plaf.basic 
javax.swing.plaf.metal 
javax.swing.plaf.multi 
javax.swing.table 
javax.swing.text 
javax.swing.text.html 
javax.swing.text.html.parser 
javax.swing.text.rtf 
javax.swing.tree 
javax.swing.undo

Eine umfangreichere Dokumentation des Swing-API finden Sie im Anhang.

11.2 Swing und AWT im Vergleich

Um es noch einmal zu betonen: Swing ist eine Erweiterung des AWTs. Das bedeutet, viele bisherige Klassen, Methoden und Techniken sind unter Swing verbessert und erweitert worden. Dabei wurde bei Methoden vielfach der Name beibehalten (wenn die Methode in einer neuen Klasse verwendet wird) und/oder nur eine neue Methodenunterschrift eingeführt (Stichwort Polymorphismus). Bei einigen Klassen wurde nur ein neuer Konstruktor eingeführt. Im Allgemeinen wurden neue Klassen eingeführt, die bisherige Techniken unter dem gleichen Namen bereitstellen und/oder Techniken einführen, deren Bezeichner aus dem Vorgänger herleitbar ist. So basieren viele Swing-Klassen auf den gleichen Superklassen wie AWT-Klassen. Beispielsweise ist die Swing-Klasse JToolBar ein direkter Nachkomme von Container. Viele Swing-Klassen sind auch direkt aus alten AWT-Klassen abgeleitet. Diese direkte oder indirekte Verwandtschaft dokumentiert sich oft im Namen. Viele Klassen bekommen bei verwandter Funktionalität einfach ein J vorangestellt. Aus Button unter dem AWT wird JButton, aus TextField JTextField, aus Lable JLable usw.

Sie werden sich vielleicht wundern, dass das Swing-Kapitel im Verhältnis zur Behandlung des konventionellen AWTs kürzer ist. Und das, obwohl das Swing-API erheblich umfangreicher als das AWT-API ist. Um es etwas drastisch zu formulieren - wenn man alle Details zu Swing behandeln wollte, könnte das gesamte Buch damit gefüllt werden. Das ist aber weder sinnvoll noch notwendig. Viele Details würden sich wiederholen, sodass wir uns hier auf eine Auswahl von wesentlichen Elementen beschränken. Entscheidend ist dabei auch, dass man bei Swing sämtliche Erkenntnisse aus den bisherigen Abhandlungen über das AWT (GUI-Gestaltung verbunden mit dem neuen Eventhandling) schlicht zusammenbringen muss und einfach übertragen kann. Wenn man konkret unter dem Swingkonzept programmieren möchte, ordnet man seine UI-Elemente wie gehabt auf einem Panel (unter Swing aus der Klasse JPanel erstellt) oder in einem auf Swing basierenden Applet an (Klasse JApplet als Superklasse). Das Swing-JPanel entspricht weitgehend dem bekannten Panel, benutzt aber wie alle Swing-Elemente keine Peer-Klasse. Außerdem werden quasi von Hause aus diverse Techniken unterstützt, die man unter dem AWT bzw. konventionellem Java »von Hand« selbst programmieren muss. Dazu zählt z.B. die Technik des Double Buffering, um das Flackern des Bildschirms zu verringern (Defaulteinstellung, die mit der Methode setBuffered(boolean)verändert werden kann).

Die meisten Swing-Klassen - etwa JMenuBar, JMenu oder JmenuItem - sind mit den Menüklassen des konventionellen AWTs eng verwandt. Die Klasse JFrame besitzt beispielsweise als direkter Nachkomme von java.awt.Frame auch sämtliche der dort besprochenen Methoden und Eigenschaften, aber natürlich auch zahlreiche Erweiterungen. Zwar lassen sich durchaus Details finden, wo Vorgänge geringfügig verändert wurden. Prinzipiell gilt aber das, was auch in der Fahrschule gilt: Wenn man mit einem bestimmten Auto den Führerschein gemacht hat, kann man mit etwas Umgewöhnung jeden anderen Wagen fahren. Wir sprechen einmal eine exemplarische Erstellung einer Swing-Oberfläche durch.

1. Als ersten Schritt sollten Sie, wenn Sie nicht im Quelltext jedes Mal voll qualifizierte Angaben machen wollen, neben den bisher üblichen Paketen noch javax.swing.* und die sonst aus dem Swing-Konzept verwendeten Pakete am Anfang importieren. Vergessen Sie dabei nicht die Klasse java.awt.event.*, wenn Sie die darauf basierenden Reaktionen behandeln wollen.
2. Danach verwenden Sie einfach Swing-Komponenten statt der bisherigen Komponenten, um die Oberfläche zu gestalten, also etwa JPanel, JMenuBar, JMenu, JMenuItem, JButton usw.
3. Die Verwendung des new-Operators erfolgt wie gehabt. Die Anordung auf dem JPanel funktioniert ähnlich wie bisher. Sie ist nur in einigen Details erweitert worden, die aber überwiegend auch im AWT schon möglich sind (dort gibt es aber noch viele Techniken, die explizit unter Swing so nicht mehr funktionieren). Swing stellt einige neuen Methoden und Layoutmanager bereit, die die Anordnung und das Aussehen erweitern. Dort steckt eine wesentliche Erweiterung der Gestaltungsmöglichkeiten. So erfolgt die Platzierung von Komponenten auf einem Container immer noch über die add()-Methode (wobei die ganz alte Variante mit nur einem Parameter unter Swing keine Verwendung mehr findet). Sie sollten allerdings bei sämtlichen Aktionen, die das Layout einer Oberfläche berühren, die dem Panel zugrundeliegende Gestaltung abfragen. Mit der Methode public Container getContentPane() bekommen Sie als Rückgabewert Informationen über das zugrunde liegende Layoutkonzept. Sie können, da ein Objekt vom Typ JRootPane zurückgegeben wird, direkt die add()-Methode auf die Methode per Punktnotation anwenden: getContentPane().add(). In der Dokumentation des jeweiligen Containers finden Sie die Details, auf die Sie achten müssen.
4. Die Erstellung von Funktionalitäten in Form von eigenen Klassen und Methoden ist im Grundsatz identisch (außer, dass Sie mehr Möglichkeiten als bisher haben).
5. Das Eventhandling muss unter Swing immer auf dem 1.1-Modell aufgebaut werden. Dazu gilt es, die passenden Listener-Klassen zu entwerfen und das zugehörige Eventhandling zu erstellen.

Das war es eigentlich. Nur sollte beachtet werden, dass die Swing-Komponenten oft zahlreiche Eigenschaften und Ereignisbehandlungsmethoden beinhalten, die wir aus oben genannten Gründen nicht vollständig durchsprechen. Die API-Dokumentation gibt aber bei Bedarf dazu mehr Informationen.

Die Aussagen zu Swing lassen sich auch auf andere neue Techniken und Methoden übertragen. Es wird jeoch sehr oft vorkommen, dass Sie eine als deprecated gekennzeichnete Methode verwenden, denn diese Veränderungen sind fließend und finden ständig statt. Jede (Zwischen-)-Version von Java wird einige Methoden leicht verändern und den Vorgänger als deprecated kennzeichnen, ihn gleichwohl weiter unterstützen. Wenn Sie eine als deprecated gekennzeichnete Methode verwenden, können Sie in der aktuellsten Java-Dokumentation die Methode oder neue Variante der Methode nachschlagen, die statt dessen verwendet werden soll. Ob Sie diese dann verwenden oder nicht, hängt davon ab, ob Sie eine möglichst große Zielgruppe erreichen wollen oder eine leistungsfähigere und meist stabilere Variante vorziehen. Um aber nicht falsch verstanden zu werden - wenn kein entscheidendes Argument dagegen spricht, ist natürlich die neuere Lösung vorzuziehen.

11.2.1 Einige Swing-Probleme

Swing erweitert wie gesagt das AWT erheblich. Die Verwendung von Swing beinhaltet aber auch einige Probleme. Dies betrifft insbesondere die Performance und den Ressourcenbedarf. Swing-Applikationen sind in der Regel langsamer als vergleichbare Anwendungen, die auf dem reinen AWT basieren. Sie benötigen auch mehr Ressourcen in Hinblick auf den Prozessor und dem Hauptspeicher. Dazu kommen Berichte vergangener Java-Versionen, dass Swing-Appliaktionen die Speicherbereinigung durch den Garbage Collector nicht korrekt befolgt haben. Und nicht zuletzt sollten für Applets die im Buch schon mehrfach beschriebenen Probleme mit Java-Techniken jenseits vom JDK 1.0.2 beachtet werden.

11.3 Swing in der Praxis

Lassen Sie uns einige Swing-Beispiele durchspielen, um die Swing-Philosophie in der Praxis zu sehen. Dabei werden wir die im AWT-Kapitel behandelten Elemente direkt einsetzen.

11.3.1 Umschalten von Look and Feel

Um das Look and Feel von Swing-Applikationen zur Laufzeit umzuschalten, muss man einfach die setLookAndFeel()-Methode verwenden, wie wir es in dem folgenden Beispiel tun. Darüber wird der UIMangager (eine Klasse zum Anpassen des Look and Feel) angewiesen, das Look and Feel entsprechend der der Methode übergebenen Parameter umzuschalten. Windows-Anwender können beispielsweise zwischen Motif, dem Windows-Standard und Metal wählen. Dabei sollte man unbedingt beachten, dass das Wechseln eines Look and Feel einige Exceptions auslösen kann. Wir fangen diese im nachfolgenden Beispiel ab. Das Beispiel beinhaltet nur drei Button, die das Look and Feel jeweils auswählen und dann setzen. Beachten Sie, dass das Programm auf Befehlszeilenebene beendet werden muss.

import java.awt.event.*;
import javax.swing.*;
public class LookAndFeel extends JFrame implements ActionListener {
  public LookAndFeel() {
    super();
    JPanel jBPanel = new JPanel();
    JButton jB1 = new JButton("Metal");
    jB1.addActionListener(this);
    jBPanel.add(jB1);
    JButton jB2 = new JButton("Motif");
    jB2.addActionListener(this);
    jBPanel.add(jB2);
    JButton jB3 = new JButton("Windows");
    jB3.addActionListener(this);
    jBPanel.add(jB3);
    getContentPane().add("South", jBPanel);
  }
  public void actionPerformed(ActionEvent event) {
    String cmd = event.getActionCommand();
    try {
      // Look and Feel auswählen 
      String laf = "unknown";
      if (cmd.equals("Metal")) {
        laf = 
 "javax.swing.plaf.metal.MetalLookAndFeel";
      } else if (cmd.equals("Motif")) {
        laf = 
 "com.sun.java.swing.plaf.motif.MotifLookAndFeel";
      } else if (cmd.equals("Windows")) {
        laf = 
"com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
      }
      //Look and Feel umschalten
      UIManager.setLookAndFeel(laf);
      SwingUtilities.updateComponentTreeUI(this);
    } catch (UnsupportedLookAndFeelException e) {
      System.err.println(e.toString());
    } catch (ClassNotFoundException e) {
      System.err.println(e.toString());
    } catch (InstantiationException e) {
      System.err.println(e.toString());
    } catch (IllegalAccessException e) {
      System.err.println(e.toString());
    }
  }
  public static void main(String[] args) {
    LookAndFeel frame = new LookAndFeel();
    frame.setLocation(100, 100);
    frame.pack();
    frame.setVisible(true);
  }  }

Abbildung 11.1:  Metal-Look

Abbildung 11.2:  Motif-Look

Abbildung 11.3:  Windows-Look

Mehr zu den Hintergründen, insbesondere zu Events, folgt im Laufe des Kapitels. Ansonsten wollen wir aber auf das dynamische Umschalten des Look and Feel im Folgenden meist verzichten.

11.3.2 Swing und Applets

Swing lässt sich im Prinzip leicht in Verbindung mit Applets realisieren. Als Erstes wollen wir ein ganz einfaches Applet nach dem Swing-Konzept erstellen, das nur ein paar Komponenten auf der Oberfläche anordnet (ohne Eventhandling). Dabei wird die Java-Syntax kaum Probleme bereiten. Sie kennen alle Komponenten - es ist immer nur ein vorangestelltes J zu dem bisherigen Fall verschieden. Beachten Sie, dass die grundsätzlichen Tools (Layoutmanager, Konstruktoren usw.) so gut wie identisch zu dem konventionellen Fall sind. Wichtigster Unterschied bei dem Beispiel ist, dass die Oberfläche betreffende Aktionen über die Methode getContentPane() »abgefedert« werden, damit das Layout sich auf die spezifisichen Bedingungen der Plattform einstellen kann. Das Beispiel wird dennoch Probleme machen, die von ganz anderer Seite herrühren.

import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import javax.swing.*;
public class SwingApplet1 extends JApplet {
 JButton button1;
 JButton button2;
 JCheckBox Klick1;
 JLabel meinLabel;
 public void init()  {
 getContentPane().setLayout(new FlowLayout());
 button1 = new JButton("Ja");
 button2 = new JButton("Nein");
 Klick1 = new JCheckBox("Selektier mich");
 meinLabel = new JLabel(
 "Ein einfaches Applet nach dem Swingkonzept");
 getContentPane().add(button1);
 getContentPane().add(button2);
 getContentPane().add(Klick1);
 getContentPane().add(meinLabel);
 }  }

Sie benötigen zur Referenzierung eine übliche HTML-Datei mit dem <APPLET>-Tag, also eine Datei der folgenden Form:

<HTML>
<BODY>
<APPLET CODE = "SwingApplet1.class"
  WIDTH = 300  HEIGHT = 200></APPLET>
</BODY>
</HTML>

Abbildung 11.4:  Das einfache Swing-Applet im Appletviewer

Das Beispiel ist wirklich einfach und enthält nichts, was so auf den ersten Blick Probleme machen könnte. Oder doch? Dann laden Sie das Applet doch einmal in den Netscape Navigator 4.7 (ein wirklich nicht sonderlich alter Browser). Der Browser meldet einen Fehler.

Abbildung 11.5:  Probleme mit dem Swing-Applet im Navigator 4.7

Erst der Navigator 6.0 kommt mit dem Swing-Applet zurecht. Ebenso hat der Opera 5 keine Probleme.

Abbildung 11.6:  Keine Probleme mehr im Navigator 6

Das Problem tritt aber auch im Internet Explorer (selbst in der Version 5.5) auf. Dieser kommt erst dann mit dem Applet zurecht, wenn die - sehr kritische1 - Referenzierung über das <OBJECT>-Tag erfolgt. Für den Navigator 4.7 referenziert man mit dem <EMBED>-Tag und verschachtelt die HTML-Datei so, dass jeder Browser automatisch seinen richtigen Tag auswählt. Die Referenzierung sieht dann so aus:

<HTML>
<BODY>
<OBJECT classid=
"clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" 
WIDTH = 300 HEIGHT = 200  codebase="http://java.sun.com/products/plugin/1.3/jinstall-13-
win32.cab#Version=1,3,0,0">
<PARAM NAME = CODE VALUE = "SwingApplet1.class" >
<PARAM NAME="type" VALUE="application/x-java-applet;version=1.3">
<PARAM NAME="scriptable" VALUE="false">
<COMMENT>
<EMBED type="application/x-java-applet;version=1.3"  CODE = "SwingApplet1.class" WIDTH = 300 
HEIGHT = 200  scriptable=false pluginspage="http://java.sun.com/products/plugin/1.3/plugin-
install.html"><NOEMBED></COMMENT>
</NOEMBED></EMBED>
</OBJECT>
</BODY>
</HTML>

Der in Kapitel 1 bzw. Kapitel 3 (JDK-Tools) besprochene HTML-Konverter von Sun hilft erheblich bei der Konvertierung von einer Applet-Referenzierung mit <APPLET> zu einer <OBJECT>-Referenzierung.

Diese Probleme bei der Verwendung von Java-Techniken, die jenseits von Java 1.0.2 anzusiedeln sind, macht in Verbindung mit Applets umfangreiche Tests in verschiedenen Browsern notwendig. Oder Sie müssen in den (sehr) sauren Apfel beißen und das <OBJECT>- bzw. <EMBED>-Tag verwenden.

Swing-Applet-Beispiel mit Interaktion durch Buttons und Radiobuttons

Kommen wir aber zu einem etwas komplexeren Applet, mit dem wir auch das Eventhandling unter Swing demonstrieren wollen. Das Applet fügt wieder einige Swing-Komponenten in eine Oberfläche ein und reagiert auf Interaktionen durch den Anwender (JButton und JRadioButton). Dabei werden wir hier ausnahmsweise mit Standard-Adaptern arbeiten. Wir beschränken uns auf Anklicken mit der Maus, aber das Verfahren ist allgemeingültig.

Grundsätzlich werden wir uns in dem Kapitel meist auf die Standardereignisse der Swing- Komponenten beschränken. Die verschiedenen Komponenten besitzten meist jedoch zahlreiche mögliche Ereignisse, die bei Bedarf registriert und dann überschrieben werden können. Diese finden Sie allesamt in der API-Dokumentation beschrieben.
import javax.swing.*;
import java.awt.*;
public class SwingApplet2 extends JApplet {
// DEKLARIEREN der CONTROLS
JButton jB1 = new JButton();
JButton jB2 = new JButton();
JRadioButton jRB1 = new JRadioButton();
JRadioButton jRB2 = new JRadioButton();
public void init() {
//  Layout setzen
getContentPane().setLayout(new FlowLayout());
// Die nachfolgende Zeile ist reine 
// Vorsichtsmaßnahme. 
// Sie unterbindet die Meldung 
// "Swing: checked access to system event queue",
// die bei gewissen Swing-Akionen in einige 
// Browsern erzeugt wird.
getRootPane().putClientProperty("defeatSystemEventQueueCheck", Boolean.TRUE);
// INIT_CONTROLS
// Hintergrundfarbe setzen
getContentPane().setBackground(java.awt.Color.red);
// Größe Applet
setSize(450,275);
// Belegen der CONTROLS mit Werten
// danach hinzufügen.
jB1.setText("Mache Gross");
getContentPane().add(jB1);
jB2.setText("Mache klein");
getContentPane().add(jB2);
jRB1.setText("Rot");
jRB1.setSelected(true); // vorselektiert
getContentPane().add(jRB1);
jRB2.setText("Blau");
getContentPane().add(jRB2);
// REGISTIEREN und EINRICHTEN der LISTENER
// Erster Schritt: Erzeugen eines Objekts der 
// Klasse, wo die Auswertung der Events erfolgt.
MausReak meineMaus = new MausReak();
// Registrieren der Listener 
// - hier nur Mauslistener
jB1.addMouseListener(meineMaus);
jB2.addMouseListener(meineMaus);
jRB1.addMouseListener(meineMaus);
jRB2.addMouseListener(meineMaus);
}
// Klasse zum Auswerten der Reaktionen
class MausReak extends java.awt.event.MouseAdapter {
// Die Methode ruft je nach angeklicktem Control
// die entsprechende zu behandelnde Methode auf.
public void mouseClicked(java.awt.event.MouseEvent event) {
Object object = event.getSource();
if (object == jB1) jB1_mouseClicked(event);
else if (object == jB2) jB2_mouseClicked(event);
else if (object == jRB1) jRB1_mouseClicked(event);
else if (object == jRB2) jRB2_mouseClicked(event);
}  }
void jB1_mouseClicked(java.awt.event.MouseEvent event) {
// vergrössere
 this.setSize(600,400);
}
void jB2_mouseClicked(java.awt.event.MouseEvent event) {
// klein
  this.setSize(200,100);
}
void jRB1_mouseClicked(java.awt.event.MouseEvent event) {
// Setze Hintergrundfarbe des Applets auf rot.
// Beachten Sie, dass der andere Radiobutton 
// explizit auf false gesetzt werden muss.
getContentPane().setBackground(java.awt.Color.red);
jRB2.setSelected(false); 
}
void jRB2_mouseClicked(java.awt.event.MouseEvent event) {
// Setze Hintergrundfarbe des Applets auf blau.
// Beachten Sie, dass der andere Radiobutton
// explizit auf false gesetzt werden muss.
getContentPane().setBackground(java.awt.Color.blue);
jRB1.setSelected(false); 
}  }

Das Beispiel vergrößert das Applet jeweils bei Klick auf den entsprechenden Button bzw. verkleinert es wieder (nur im Appletviewer!). Die Radiobuttons wechseln die Hintergrundfarben des Applets. Beachten Sie die Kommentare im Quelltext, die die entscheidenden Stellen erklären.

Abbildung 11.7:  Groß und rot

Abbildung 11.8:  Klein und blau

Swing-Textfelder und absolute Positionierung

Sie können unter Swing auch dafür sorgen, dass Komponenten auf der Oberfläche absolut positioniert und in der Größe festgelegt werden. Dafür gibt es die Methode public void setBounds(int x, int y, int breite, int hoehe) aus der Klasse java.awt.Component, die über die Angabe der linken oberen Ecke einer Komponente und seiner Breite/Höhe dafür sorgen.

Wir werden dies in dem nächsten Beispiel, wo wir den Quelltext von eben erweitern wollen, anwenden. Aber Vorsicht, solche absoluten Angaben hebeln einen zentralen Vorteil von Java wieder aus: die Anpassung an äußere Umstände. Dies wird das Beispiel demonstrieren. Das Beispiel zeigt aber auch den Sinn von solchen Festlegungen der absoluten Größe (zumindest von einzelnen Komponenten der Oberfläche). Wir belegen ein Swing-Textfeld (JTextField) abwechselnd mit einem Text und löschen diesen mit einer anderen Schaltfläche wieder. Da das Textfeld bei der Erzeugung und Platzierung auf dem Panel noch leer ist, würde ein Layout-Manager - ohne die feste Vorgabe der Größe - das Textfeld unter Umständen ganz klein darstellen. Bei einem Belegen müsste das Panel jedes Mal neu gezeichnet werden.

Das Beispiel reagiert gelegentlich etwas »träge« auf Mausklicks. Eventuell müssen Sie etwas warten oder noch einmal klicken.
import javax.swing.*;
import java.awt.*;
public class SwingApplet3 extends JApplet {
// DEKLARIEREN der CONTROLS
JButton jB1 = new JButton();
JButton jB2 = new JButton();
JButton jB3 = new JButton();
JButton jB4 = new JButton();
JTextField jTF1 = new JTextField();
JRadioButton jRB3 = new JRadioButton();
JRadioButton jRB4 = new JRadioButton();
public void init() {
getRootPane().putClientProperty(
"defeatSystemEventQueueCheck", Boolean.TRUE);
// INIT_CONTROLS
// Eventuelles Layout zurücksetzen
getContentPane().setLayout(null);
// Hintergrundfarbe setzen
getContentPane().setBackground(java.awt.Color.red);
// Größe Applet
setSize(450,350);
// Belegen der CONTROLS mit Werten
// danach hinzufügen.
// Als dritten Schritt legen wir in dem 
// Beispiel die exakte Position und Größe 
// des Controls fest
jB1.setText("vergroessere");
getContentPane().add(jB1);
jB1.setBounds(60,220,140,50);
jB2.setText("verkleinere");
getContentPane().add(jB2);
jB2.setBounds(228,220,140,50);
jB3.setText("Schreibe Text");
getContentPane().add(jB3);
jB3.setBounds(60,168,140,50);
jB4.setText("Loesche Text");
getContentPane().add(jB4);
jB4.setBounds(228,168,140,50);
getContentPane().add(jTF1);
jTF1.setBounds(60,24,324,38);
jRB3.setText("Rot");
jRB3.setSelected(true); // vorselektiert
getContentPane().add(jRB3);
jRB3.setBounds(60,96,141,22);
jRB4.setText("Blau");
getContentPane().add(jRB4);
jRB4.setBounds(228,96,141,22);
// REGISTIEREN und EINRICHTEN der LISTENER
// Erster Schritt: Erzeugen eines Objekts der 
// Klasse, wo die Auswertung der Events erfolgt.
jRB meineMaus = new jRB();
// Registrieren der Listener 
// - hier nur Mauslistener
jB1.addMouseListener(meineMaus);
jB2.addMouseListener(meineMaus);
jB3.addMouseListener(meineMaus);
jB4.addMouseListener(meineMaus);
jRB3.addMouseListener(meineMaus);
jRB4.addMouseListener(meineMaus);
}
// Klasse zum Auswerten der Reaktionen
class jRB extends java.awt.event.MouseAdapter {
// Die Methode ruft je nach angeklicktem Control
// die entsprechende Methode zum Behandeln auf.
public void mouseClicked(java.awt.event.MouseEvent event){
Object object = event.getSource();
if (object == jB1)
jB1_mouseClicked(event);
else if (object == jB2)
jB2_mouseClicked(event);
else if (object == jB3)
jB3_mouseClicked(event);
else if (object == jB4)
jB4_mouseClicked(event);
else if (object == jRB3)
jRB3_mouseClicked(event);
else if (object == jRB4)
jRB4_mouseClicked(event);
}  }
void jB1_mouseClicked(java.awt.event.MouseEvent event) {
// vergrößere
 this.setSize(600,400);
}
void jB2_mouseClicked(java.awt.event.MouseEvent event) {
// verkleinere
  this.setSize(200,100);
}
void jB3_mouseClicked(java.awt.event.MouseEvent event) {
// Schreibe Text
 jTF1.setText("Ei gude wie?");
}
void jB4_mouseClicked(java.awt.event.MouseEvent event) {
// Lösche Text
 jTF1.setText("");
}
void jRB3_mouseClicked(java.awt.event.MouseEvent event) {
getContentPane().setBackground(java.awt.Color.red);
jRB4.setSelected(false); 
}
void jRB4_mouseClicked(java.awt.event.MouseEvent event) {
getContentPane().setBackground(java.awt.Color.blue);
jRB4.setSelected(false); 
}  }

Das Beispiel vergrößert wieder jeweils bei Klick auf den entsprechenden Button das Applet bzw. verkleinert es wieder (nur im Appletviewer!). Dabei werden die Komponenten allerdings festgehalten, was die Probleme mit dieser Technik zeigen soll. Die beiden neuen Buttons schreiben und löschen Text im Textfeld. Die Radiobuttons wechseln wieder die Hintergrundfarben des Applets.

Abbildung 11.9:  Original-Layout

Abbildung 11.10:  Mit Text, blau und Komponenten leicht zu weit links

Abbildung 11.11:  Hier knallt es  im Layout

11.4 Eigenständige Applikationen und Swing

Swing ist selbstverständlich nicht auf Applets beschränkt. Im Gegenteil - bei eigenständigen Applikationen treten die Probleme der Inkompatibilität von Browsern nicht auf. Hauptsächlich muss man die Applikation - statt auf Frame - auf JFrame aufbauen. Wir werden jetzt ein kleines Beispiel durchspielen, wo wir diese Technik in Verbindung mit einer eigenständigen Applikation einsetzen. Es handelt sich um eine Swing-Applikation, wo nur ein Button vorhanden ist. Dieser beendet das Programm.

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class SwingAppl extends JFrame {
  JButton jButton1 = new JButton();
  FlowLayout flowLayout1 = new FlowLayout();
  public SwingAppl() {
      initial();
  }
  public static void main(String[] args) {
    SwingAppl swingAppl = new SwingAppl();
    swingAppl.setSize(200,100);
    swingAppl.setVisible(true);
  }
  private void initial() {
    jButton1.setActionCommand("Ende");
    jButton1.setText("Ende");
    jButton1.addActionListener(
  new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        jButton1_actionPerformed(e);  }  });
    getContentPane().setLayout(flowLayout1);
    setTitle("Swing-Applikation");
    getContentPane().add(jButton1, null);
  }
  void jButton1_actionPerformed(ActionEvent e) {
   System.exit(0);
  }  }

Abbildung 11.12:  Eine einfache Swing-Applikation

11.4.1 Eine Swing-Applikations-Schablone

Nachfolgend finden Sie eine Schablone für eine eigenständige Swing-Applikation, wo ein wenig mehr Funktionalität realisiert ist. Sie erstellt ein Fenster, installiert einige Reaktionsmöglichkeiten und einen Ende-Dialog. Darauf aufbauend können Sie funktionstüchtige Swing-Applikationen erstellen.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
/**
 Eine Basis-Swing-Schablone für eine Applikation.
 */
public class SwingApplikaSchablone extends JFrame {
public SwingApplikaSchablone() {
// INIT_CONTROLS
setTitle("Swing-Applikation");
setDefaultCloseOperation(javax.swing.JFrame.DO_NOTHING_ON_CLOSE);
getContentPane().setLayout(new BorderLayout(0,0));
setSize(500,300);
setVisible(false);
// REGISTER_LISTENERS
Fenst meinFenst = new Fenst();
this.addWindowListener(meinFenst);
Akt meineAktion = new Akt();
}
/* Erstellt eine neue Instanz von SwingApplikaSchablone mit dem im Konstruktor angebenen 
Titel. */
public SwingApplikaSchablone(String sTitle) {
this();
setTitle(sTitle);
}
static public void main(String args[]) {
try {
// Optional Anpassen an das Look and Feel
// des Nativesystems.
 /*
 try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
 } 
 catch (Exception e) { 
 }
 */
// Neue Instanz des Applikationsfensters und 
// sichtbar machen.
 (new SwingApplikaSchablone()).setVisible(true);
 } 
catch (Throwable t) {
t.printStackTrace();
// Ende mit Fehlermeldung im Falle von Problemen.
System.exit(1);
}  }
void exitApplication() {
try {
 // Anzeige eines Ende-Dialogs
 int antwort = JOptionPane.showConfirmDialog(this, 
 "Wollen Sie wirklich beenden?", 
 "Swing-Applikation - Exit" , 
 JOptionPane.YES_NO_OPTION, 
 JOptionPane.QUESTION_MESSAGE);
if (antwort == JOptionPane.YES_OPTION) {
 this.setVisible(false); // Verstecke Frame
 this.dispose(); // Freigabe Systemressourcen
 System.exit(0); // Ende
}  } 
catch (Exception e) {
}  }
class Fenst extends java.awt.event.WindowAdapter {
public void windowClosing(java.awt.event.WindowEvent event) {
Object object = event.getSource();
if (object == SwingApplikaSchablone.this)
SwingApplikaSchablone_windowClosing(event);
}  }
void SwingApplikaSchablone_windowClosing(java.awt.event.WindowEvent event) {
SwingApplikaSchablone_windowClosing_Interaction1(event);
}
void SwingApplikaSchablone_windowClosing_Interaction1(java.awt.event.WindowEvent event) {
try {
this.exitApplication();
} 
catch (Exception e) {
}  }
class Akt implements java.awt.event.ActionListener {
public void actionPerformed(java.awt.event.ActionEvent event) {
Object object = event.getSource();
}  }
}

Abbildung 11.13:  Die Schablone

Abbildung 11.14:  Der zugehörige Swing-Ende-Dialog

Beachten Sie die Methode showConfirmDialog(). Diese gehört wie zahlreiche weitere Methoden zum Anzeigen von verschiedenartigen Dialogfenstern zur Klasse public class JOptionPane extends JComponent implements Accessible. Dort finden Sie unter anderem die folgenden Dialogmethoden:

static int showConfirmDialog(Component parentComponent, Object message) 
static int showConfirmDialog(Component parentComponent, Object message, String title, int 
optionType) 
static int showConfirmDialog(Component parentComponent, Object message, String title, int 
optionType, int messageType) 
static int showConfirmDialog(Component parentComponent, Object message, String title, int 
optionType, int messageType, Icon icon) 
static String showInputDialog(Component parentComponent, Object message) 
static String showInputDialog(Component parentComponent, Object message, String title, int 
messageType) 
static Object showInputDialog(Component parentComponent, Object message, String title, int 
messageType, Icon icon, Object[] selectionValues, Object initialSelectionValue) 
static String showInputDialog(Object message) 
static int showInternalConfirmDialog(Component parentComponent, Object message) 
static int showInternalConfirmDialog(Component parentComponent, Object message, String 
title, int optionType) 
static int showInternalConfirmDialog(Component parentComponent, Object message, String 
title, int optionType, int messageType) 
static int showInternalConfirmDialog(Component parentComponent, Object message, String 
title, int optionType, int messageType, Icon icon) 
static String showInternalInputDialog(Component parentComponent, Object message) 
static String showInternalInputDialog(Component parentComponent, Object message, String 
title, int messageType) 
static Object showInternalInputDialog(Component parentComponent, Object message, String 
title, int messageType, Icon icon, Object[] selectionValues, Object initialSelectionValue) 
static void showInternalMessageDialog(Component parentComponent, Object message) 
static void showInternalMessageDialog(Component parentComponent, Object message, String 
title, int messageType) 
static void showInternalMessageDialog(Component parentComponent, Object message, String 
title, int messageType, Icon icon) 
static int showInternalOptionDialog(Component parentComponent, Object message, String 
title, int optionType, int messageType, Icon icon, Object[] options, Object initialValue) 
static void showMessageDialog(Component parentComponent, Object message) 
static void showMessageDialog(Component parentComponent, Object message, String title, int 
messageType) 
static void showMessageDialog(Component parentComponent, Object message, String title, int 
messageType, Icon icon) 
static int showOptionDialog(Component parentComponent, Object message, String title, int 
optionType, int messageType, Icon icon, Object[] options, Object initialValue)

11.5 Swing-Komponenten im Detail

Schauen wir uns anhand diverser Beispiele nun die wichtigsten (noch fehlenden) Swingkomponenten an und wie sie von der Syntax her integriert werden können. Die Ähnlichkeiten zu den konventionellen AWT-Komponenten sind offensichtlich, aber es gibt auch zahlreiche Neuerungen von Swing, denen keine Entsprechungen im AWT gegenüberstehen.

Sie finden hier keine in je einem nummerierten Unterkapitel aufgeführten einzelnen Komponenten. Beim Aufbau dieses Abschnitts und der Zusammensetzung der besprochenen Swing-Komponenten soll explizit das AWT-Kapitel als Grundlage dienen, das einen solchen Aufbau realisiert. Motivation ist, die Komponenten in Form von praktischen Beispielen mit gut zusammenpassenden Elementen einzusetzen.

Swing-Panels und Swing-Labels

Das erste Beispiel ist eine kleine Erweiterung unserer ersten Swing-Applikation. Zusätzlich zu dieser arbeiten wir mit Swing-Panels und einem Swing-Label, das dynamisch beschriftet und gelöscht werden soll. Also ein Beispiel, das wir so auch mit dem AWT realisiert haben. Wir verwenden dabei anonyme Klassen zum Eventhandling.

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class SwingAppl2 extends JFrame {
  BorderLayout borderLayout1 = new BorderLayout();
  JPanel jPanel1 = new JPanel();
  FlowLayout flowLayout1 = new FlowLayout();
  JButton jButton1 = new JButton();
  JButton jButton2 = new JButton();
  JButton jButton3 = new JButton();
  JLabel jLabel1 = new JLabel();
  public SwingAppl2() {
      initial();
  }
  public static void main(String[] args) {
    SwingAppl2 swingAppl = new SwingAppl2();
    swingAppl.setSize(300,100);
    swingAppl.setVisible(true);
  }
  private void initial() {
   this.getContentPane().setLayout(borderLayout1);
   this.setTitle("Swing-Applikation");
   jPanel1.setLayout(flowLayout1);
   jButton1.setText("Ende");
   jButton1.addActionListener(
  new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        jButton1_actionPerformed(e);  }  });
   jButton2.setText("Schreibe");
   jButton2.addActionListener(
  new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        jButton2_actionPerformed(e);  }  });
   jButton3.setText("Lösche");
   jButton3.addActionListener(
  new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        jButton3_actionPerformed(e);  }  });
   jLabel1.setHorizontalAlignment(
  SwingConstants.CENTER);
   this.getContentPane().add(jPanel1, 
  BorderLayout.SOUTH);
   jPanel1.add(jButton1, null);
   jPanel1.add(jButton2, null);
   jPanel1.add(jButton3, null);
   this.getContentPane().add(jLabel1, 
  BorderLayout.CENTER);
  }
  void jButton1_actionPerformed(ActionEvent e) {
   System.exit(0);
  }
  void jButton2_actionPerformed(ActionEvent e) {
  jLabel1.setText("No Pc no cry");
  }
  void jButton3_actionPerformed(ActionEvent e) {
  jLabel1.setText("");
  }  }

Abbildung 11.15:  Eine Swing-Applikation mit Panels  und Label

Ja nach Button wird das Label geschrieben oder gelöscht. Der Button ganz links beendet das Programm.

Menüs, Bildaufleisten, Slider, Progressbar und Toolbar unter Swing

Das nächste Beispiel zeigt einige weitere Swing-Techniken und -Komponenten. Etwa einen Slider (JSlider), der im Wesentlichen einer Scrollbar (also Bildlaufleiste - auch die wird in dem Beispiel verwendet) entspricht (unter Swing mit der Klasse JScrollbar realisiert) und eine Toolbar zum Anordnen von Komponenenten (JToolbar). Dazu kommt noch eine Progressbar (ein Fortschrittsbalken, der anzeigt, wie weit ein Prozess gediehen ist) (JProgressBar), die man zum Anzeigen des Fortschritts einer Aktion verwendet (beispielsweise um den Fortschritt einer Installation anzuzeigen). Zusätzlich wird ein Menü unter Swing realisiert. Beachtet werden sollte zudem, dass das Beispiel Bilder für Schaltflächen verwendet, die über die Klasse ImageIcon und und Methode setIcon() realisiert werden. Ebenso wird die Verwendung einer Quick-Info für Komponenten demonstriert (setToolTipText()). Das Beispiel besteht aus drei Dateien und ist etwas umfangreicher, aber ausführlich im Quelltext dokumentiert.

Datei Nummer eins ist die eigentliche Applikation und recht klein, denn sie ruft nur das in der zweiten Datei zwei beschriebene Fenster auf. Dabei zeigt diese Datei als kleines Bonbon, wie man eine Applikation auf dem Bildschirm zentrieren kann.

import javax.swing.UIManager;
import java.awt.*;
public class SwingAppl3 {
  boolean packFrame = false;
  /**Die Anwendung konstruieren*/
  public SwingAppl3() {
    SwingFrame1 frame = new SwingFrame1();
// Frames überprüfen, die voreingestellte Größe 
// haben, Frames packen, die nutzbare bevorzugte 
// Größeninformationen enthalten, z.B. aus ihrem 
// Layout
    if (packFrame) {
      frame.pack();
    }
    else {
      frame.validate();
    }
    // Fenster auf Bildschirm zentrieren
    Dimension screenSize = 
  Toolkit.getDefaultToolkit().getScreenSize();
    Dimension frameSize = frame.getSize();
    if (frameSize.height > screenSize.height) {
      frameSize.height = screenSize.height;
    }
    if (frameSize.width > screenSize.width) {
      frameSize.width = screenSize.width;
    }
    frame.setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - 
frameSize.height) / 2);
    frame.setVisible(true);
  }
  /** main()-Methode der Applikaiton */
  public static void main(String[] args) {
    try {
      UIManager.setLookAndFeel(
   UIManager.getSystemLookAndFeelClassName());
    }
    catch(Exception e) {
      e.printStackTrace();
    }
    new SwingAppl3();
  }  }
Die Auslagerung des Programmstarts
Datei Nummer zwei beinhaltet die wesentliche Funktionalität des Beispiels. Beachten Sie bitte 
die Kommentare im Quelltext.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.beans.*;
public class SwingFrame1 extends JFrame {
/* Die Objekte */  
  JPanel mPanel;
  JMenuBar jMBar1 = new JMenuBar();
  JMenu jMFile = new JMenu();
  JMenuItem jMFileExit = new JMenuItem();
  JMenu jMHelp = new JMenu();
  JMenuItem jMHelpAbout = new JMenuItem();
  JToolBar jToolBar = new JToolBar();
  JButton jB1 = new JButton();
  JButton jB2 = new JButton();
  ImageIcon image1;
  ImageIcon image2;
  JLabel statusZeil = new JLabel();
  BorderLayout bdrLayout1 = new BorderLayout();
  JPanel jPanel1 = new JPanel();
  BorderLayout bdrLayout2 = new BorderLayout();
  JProgressBar jPB1 = new JProgressBar();
  JScrollBar jScBr1 = new JScrollBar();
  JSlider jSld1 = new JSlider();
  JLabel jLb1 = new JLabel();
  JLabel jLb2 = new JLabel();
/* Der Konstruktor */
  public SwingFrame1() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      initial();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
  /**Initialisierung der Komponenten und Registrierung der Listener */
  private void initial() throws Exception  {
    // Swing-Panel gesetzt und initialisiert
    mPanel = (JPanel) this.getContentPane();
    mPanel.setLayout(bdrLayout1);
    // Fenstergroesse und Titelzeile
    this.setSize(new Dimension(400, 300));
    this.setTitle("SwingMuster 1");
    // Label1 dient als Statuszeile - leer setzen
    statusZeil.setText(" ");
    // Menuebar beschriften
    jMFile.setText("Datei");
    jMFileExit.setText("Beenden");
    // Listener zum Beenden über das Menü
    jMFileExit.addActionListener(
  new ActionListener()  {
      public void actionPerformed(ActionEvent e) {
        jMFileExit_actionPerformed(e);
      }
    });
    // Hilfemenü
    jMHelp.setText("Hilfe");
    jMHelpAbout.setText("Info");
    // Listener zum Aufruf des Infodialogs
    jMHelpAbout.addActionListener(
  new ActionListener()  {
      public void actionPerformed(ActionEvent e) {
        jMHelpAbout_actionPerformed(e);
      }
    });
    // Listener Button 1
    jB1.addActionListener(
  new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        jB1_actionPerformed(e);
      }
    });
    // Quick-Info für Button 1
    jB1.setToolTipText("Text im Label anzeigen");
    // Grafik für Button 1 - ein
    jB1.setIcon(new  
   ImageIcon(getToolkit().getImage("bild1.gif")));
    // Analog Button 2
    jB2.setIcon(new   
   ImageIcon(getToolkit().getImage("bild2.gif")));
// Alternative für die Referenzierung eines Icons.
// Hardcodierte Pfadangabe und Verwendung von 
// java.net.URL - AUSKOMMENTIERT
/* jB1.setIcon(new ImageIcon(new java.net.URL("file:///C:/WINNT/Profiles/Administrator/
jproject/SwingMuster1/src/swingmuster1/bild1.gif"))); */
    jB2.addActionListener(
  new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        jB2_actionPerformed(e);
      }
    });
    jB2.setToolTipText("Text im Label löschen");
    // Panel Layout setzen
    jPanel1.setLayout(bdrLayout2);
/* Slider vertikal ausrichten, Wert setzen und Listener registrieren */
    jSld1.setOrientation(JSlider.VERTICAL);
    jSld1.setValue(0);
    jSld1.addChangeListener(
  new javax.swing.event.ChangeListener() {
      public void stateChanged(ChangeEvent e) {
        jSld1_stateChanged(e);
      }
    });
    /* Label 1 formatieren und positionieren */
    jLb1.setFont(new java.awt.Font("Dialog", 0, 42));
    jLb1.setForeground(Color.red);
jLb1.setHorizontalAlignment(SwingConstants.CENTER);
  // Label 2 dito, sowie Listener registrieren
    jLb2.setFont(new java.awt.Font("Dialog", 0, 24));
jLb2.setHorizontalAlignment(SwingConstants.CENTER);
    jLb2.setText("Swing");
    jLb2.addMouseListener(
  new java.awt.event.MouseAdapter() {
      public void mouseEntered(MouseEvent e) {
        jLb2_mouseEntered(e);
      }
      public void mouseExited(MouseEvent e) {
        jLb2_mouseExited(e);
      }
    });
    // Listener für Scrollbar registrieren
    jScBr1.addAdjustmentListener(
  new java.awt.event.AdjustmentListener() {
      public void 
  adjustmentValueChanged(AdjustmentEvent e) {
        jScBr1_adjustmentValueChanged(e);
      }
    });
    // Toolbar mit Button füllen
    jToolBar.add(jB1);
    jToolBar.add(jB2);
    // Menubar füllen
    jMFile.add(jMFileExit);
    jMHelp.add(jMHelpAbout);
    jMBar1.add(jMFile);
    jMBar1.add(jMHelp);
    // Komponenten dem Fenster hinzufügen
    this.setJMenuBar(jMBar1);
    mPanel.add(jToolBar, BorderLayout.NORTH);
    mPanel.add(statusZeil, BorderLayout.SOUTH);
    mPanel.add(jPanel1, BorderLayout.CENTER);
    jPanel1.add(jPB1, BorderLayout.SOUTH);
    jPanel1.add(jScBr1, BorderLayout.EAST);
    jPanel1.add(jSld1, BorderLayout.WEST);
    jPanel1.add(jLb1, BorderLayout.CENTER);
    jPanel1.add(jLb2, BorderLayout.NORTH);
  }
  /**Aktion Beenden */
  public void 
  jMFileExit_actionPerformed(ActionEvent e) {
    System.exit(0);
  }
  /**Aktion Info - ein modaler Dialog, der immer zentriert im aufrufenden Fenster angezeigt 
wird.  */
  public void 
  jMHelpAbout_actionPerformed(ActionEvent e) {
    SwingFrame1_Infodialog dlg = 
  new SwingFrame1_Infodialog(this);
    Dimension dlgSize = dlg.getPreferredSize();
    Dimension frmSize = getSize();
    Point loc = getLocation();
    dlg.setLocation((frmSize.width - dlgSize.width) / 2 + loc.x, (frmSize.height - 
dlgSize.height) / 2 + loc.y);
    dlg.setModal(true);
    dlg.show();
  }
  /* Beenden über Schliessbutton */
  protected void processWindowEvent(WindowEvent e) {
    super.processWindowEvent(e);
    if (e.getID() == WindowEvent.WINDOW_CLOSING) {
      jMFileExit_actionPerformed(null);
    }
  }
/* Veränderung der Scrollbar - Slider, Label und Progressbar zeigen die Veränderung */
void jScBr1_adjustmentValueChanged(AdjustmentEvent e) {
   jLb1.setText((new 
  Integer(jScBr1.getValue())).toString());
   jPB1.setValue(jScBr1.getValue());
   jSld1.setValue(jScBr1.getValue());
  }
  /* Veränderung des Sliders - Scrollbar, Label und Progressbar zeigen die Veränderung */
  void jSld1_stateChanged(ChangeEvent e) {
   jLb1.setText((new 
  Integer(jSld1.getValue())).toString());
   jPB1.setValue(jSld1.getValue());
   jScBr1.setValue(jSld1.getValue());
  }
/* Button 1 betätigt - Label wird angezeigt*/
  void jB1_actionPerformed(ActionEvent e) {
  jLb2.setVisible(true);
  }
/* Button 2 betätigt - Label wird ausgeblendet*/
  void jB2_actionPerformed(ActionEvent e) {
  jLb2.setVisible(false);
  }
/* Label 2 mit der Maus überstrichen - Text in Statuszeile */
  void jLb2_mouseEntered(MouseEvent e) {
  statusZeil.setText("Das Label");
  }
/* Bereich von Label 2 mit der Maus verlassen - Text in Statuszeile wird gelöscht */
  void jLb2_mouseExited(MouseEvent e) {
  statusZeil.setText("");
  }  }

Abbildung 11.16:  Das Label und die Progressbar zeigen die Position des Sliders an.

Nun fehlt nur noch die dritte Datei, in der der Hilfedialog realisiert wird. Diese Datei arbeitet mit einem Dialogfenster und Swing, das auf JDialog basiert.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
/* Der Infodialog zu der Appplikation SwingAppl3 */
public class SwingFrame1_Infodialog extends JDialog implements ActionListener {
/* Die Komponenten */  
  JPanel pl1 = new JPanel();
  JPanel pl2 = new JPanel();
  JPanel insetsPanel1 = new JPanel();
  JPanel insetsPanel2 = new JPanel();
  JPanel insetsPanel3 = new JPanel();
  JButton bt1 = new JButton();
  JLabel imageLabel = new JLabel();
  JLabel lb1 = new JLabel();
  JLabel lb2 = new JLabel();
  JLabel lb3 = new JLabel();
  JLabel lb4 = new JLabel();
  BorderLayout bdLayout1 = new BorderLayout();
  BorderLayout bdLayout2 = new BorderLayout();
  FlowLayout flowLayout1 = new FlowLayout();
  GridLayout gridLayout1 = new GridLayout();
  String product = "";
  String version = "1.0";
  String copyright = "Copyright (c) 2001";
  String comments = "";
  JLabel jLb1 = new JLabel();
  JLabel jLb2 = new JLabel();
  JLabel jLb3 = new JLabel();
  public SwingFrame1_Infodialog(Frame parent) {
    super(parent);
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      initial();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
    pack();
  }
  /**Initialisierung der Komponenten*/
  private void initial() throws Exception  {
    this.setTitle("Info");
    setResizable(false);
    pl1.setLayout(bdLayout1);
    pl2.setLayout(bdLayout2);
    insetsPanel1.setLayout(flowLayout1);
    insetsPanel2.setLayout(flowLayout1);
    insetsPanel2.setBorder(
  BorderFactory.createEmptyBorder(
  10, 10, 10, 10));
    gridLayout1.setRows(4);
    gridLayout1.setColumns(1);
    lb1.setText("Version 1.0");
    lb3.setText(copyright);
    lb4.setText(comments);
    insetsPanel3.setLayout(gridLayout1);
    insetsPanel3.setBorder(
  BorderFactory.createEmptyBorder(
  10, 60, 10, 10));
    bt1.setText("OK");
    bt1.addActionListener(this);
    jLb1.setText("RJS EDV");
    jLb3.setText("WWW.RJS.DE");
    insetsPanel2.add(imageLabel, null);
    pl2.add(insetsPanel2, BorderLayout.WEST);
    this.getContentPane().add(pl1, null);
    insetsPanel3.add(lb1, null);
    insetsPanel3.add(lb2, null);
    insetsPanel3.add(lb3, null);
    insetsPanel3.add(lb4, null);
    insetsPanel3.add(jLb1, null);
    insetsPanel3.add(jLb2, null);
    insetsPanel3.add(jLb3, null);
    pl2.add(insetsPanel3, BorderLayout.CENTER);
    insetsPanel1.add(bt1, null);
    pl1.add(insetsPanel1, BorderLayout.SOUTH);
    pl1.add(pl2, BorderLayout.NORTH);
  }
  /* Ende über Schließbutton */
  protected void processWindowEvent(WindowEvent e) {
    if (e.getID() == WindowEvent.WINDOW_CLOSING) {
      cancel();
    }
    super.processWindowEvent(e);
  }
  /* Dialog schließen*/
  void cancel() {
    dispose();
  }
  /**Dialog bei Schalter-Ereignis schließen*/
  public void actionPerformed(ActionEvent e) {
    if (e.getSource() == bt1) {
      cancel();
    }
  }  }

Abbildung 11.17:  Der Infodialog

Das Beispiel realisiert eine recht umfangreiche Funktionalität mit diversen Feinheiten, die im Quelltext ausführlich dokumentiert sind.

Viel Funktionalität basiert auf der Methode getValue(), mit der im Allgemeinen Werte von Komponenten wie Slider oder Bildlaufleisten abgefragt werden können.

Wenn Sie die Maus über die Buttons bewegen, wird eine Quick-Info angezeigt. Dazu wird die Methode setToolTipText() verwendet.

Abbildung 11.18:  Quick-Info

Wenn Sie auf den einen Button klicken, wird das Label mit dem Text »Swing« angezeigt, ansonsten versteckt. Die Buttons haben keine Beschriftung, sondern zeigen Icons. Diese werden mit der Anweisung

jB1.setIcon(new ImageIcon(getToolkit().getImage("bild1.gif")));

gesetzt. Alternativ können Sie hier auch gut mit der Klasse java.net.URL und einer anderen Variante der Methode ImageIcon() arbeiten, wenn Sie ein Bild aus einer beliebigen URL laden. Ein Beispiel für einen hardcodierten Zugriff auf die Festplatte:

jB1.setIcon(new ImageIcon(new java.net.URL("file:///C:/WINNT/Profiles/Administrator/project/SwingMuster1/src/swingmuster1/bild1.gif")));

Unter Verwendung des http-Protokolls ist dies auch mit eine beliebigen Internet-URL möglich.

Auch das Label mit dem Text »Swing« besitzt eine Funktionalität. Wenn der Mauszeiger den Bereich überstreicht, wird in der Statuszeile ein Text angezeigt.

Abbildung 11.19:  Überstreichen des Labels bewirkt eine Textausgabe in der Statuszeile.

Das Menü der Applikation ermöglicht das Beenden des Programms und die Anzeige eines Infodialogs.

Abbildung 11.20:  Das Menü - Beachten Sie, dass das Label mit dem Button ausgeblendet wurde

Popup-Menüs, Checkboxen, Listenfelder, Textfelder, Toggle-Buttons und JTabbedPanes

Das vorletzte Beispiel zum Thema Swing soll den Einsatz von Popup-Menüs (Klasse JPopupMenu), Checkboxen (JCheckBox), Listenfeldern (JComboBox), Textfeldern (JTextArea) und Toggle-Buttons demonstrieren. Toggle-Buttons basieren auf der Klasse JToggleButton und erweitern neben einigen zusätzlichen Eigenschaften im Wesentlichen normale Buttons um die Eigenschaft, einen gedrückten Status anzeigen zu können. Dazu kommt der Einsatz von Registerblättern, wie sie beispielsweise aus Excel oder den verschiedensten Dialogfenstern unter Windows bekannt sind. Damit ist es möglich, in einem Fensterbereich abwechselnd verschiedene Inhalte anzuzeigen. Diese Registerblätter werden als ein besonderes Swing-Panel realisiert, das auf der Klasse JTabbedPane aufbaut.

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class VerschiedeneSwingKomponenten extends JFrame {
  // Die Komponenten
  BorderLayout borderLayout1 = new BorderLayout();
    // Container für Tabs
  JTabbedPane jTabbedPane1 = new JTabbedPane();
  JPanel jPanel1 = new JPanel();
  JPanel jPanel2 = new JPanel();
  BorderLayout borderLayout2 = new BorderLayout();
  JPanel jPanel3 = new JPanel();
  FlowLayout flowLayout1 = new FlowLayout();
    // Toggle-Button
  JToggleButton jToggleButton1 = new JToggleButton();
  BorderLayout borderLayout3 = new BorderLayout();
  JPanel jPanel4 = new JPanel();
  JPanel jPanel5 = new JPanel();
  JToggleButton jToggleButton2 = new JToggleButton();
  JLabel jLabel1 = new JLabel();
  BorderLayout borderLayout4 = new BorderLayout();
  JPanel jPanel6 = new JPanel();
    // Checkbox
  JCheckBox jCheckBox1 = new JCheckBox();
  JPanel jPanel7 = new JPanel();
  JPanel jPanel8 = new JPanel();
    // TextArea
  JTextArea jTextArea1 = new JTextArea();
  BorderLayout borderLayout5 = new BorderLayout();
    // Combobox
  JComboBox jComboBox1 = new JComboBox();
  JLabel jLabel2 = new JLabel();
    // Popup-Menü
  JPopupMenu jPopupMenu1 = new JPopupMenu();
  JMenuItem jMenuItem1 = new JMenuItem();
  // Die main()-Methode
  public static void main(String[] args) {
  VerschiedeneSwingKomponenten u = new VerschiedeneSwingKomponenten();
  u.setSize(300,300);
  u.show();
  }
  // Konstruktor
  public VerschiedeneSwingKomponenten() {
    try {
      initial();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
    // Initialisierung
  private void initial() throws Exception {
    this.getContentPane().setLayout(borderLayout1);
    jPanel1.setLayout(borderLayout2);
    jPanel3.setLayout(flowLayout1);
    jToggleButton1.setText("Übertrage");
    jToggleButton1.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        jToggleButton1_actionPerformed(e);
      }  });
    jPanel2.setLayout(borderLayout3);
    jToggleButton2.setText("Ende");
    jToggleButton2.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        jToggleButton2_actionPerformed(e);
      }
    });
    jPanel4.setLayout(borderLayout4);
    jCheckBox1.setSelected(true);
    jCheckBox1.setText("Text anzeigen");
    jCheckBox1.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        jCheckBox1_actionPerformed(e);
      }  });
    jPanel8.setLayout(borderLayout5);
    jLabel2.setText("Textmuster");
    jComboBox1.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        jComboBox1_actionPerformed(e);
      }  });
      // Zeilenumbruch in TextArea erlauben
    jTextArea1.setLineWrap(true);
    jMenuItem1.setText("Übertragen");
    jMenuItem1.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        jMenuItem1_actionPerformed(e);
      }  });
    jPanel3.addMouseListener(new java.awt.event.MouseAdapter() {
      public void mouseClicked(MouseEvent e) {
        jPanel3_mouseClicked(e);
      }  });
      // Tab-Container hinzufügen
    this.getContentPane().add(jTabbedPane1, BorderLayout.CENTER);
    jTabbedPane1.add(jPanel1, "Text eintragen");
    jPanel1.add(jPanel3, BorderLayout.NORTH);
    jPanel3.add(jToggleButton1, null);
    jPanel1.add(jPanel7, BorderLayout.SOUTH);
    jPanel7.add(jLabel2, null);
      // Listenfeld 4 Einträge hinzufügen
    jComboBox1.addItem(makeObj("Muster 1"));
    jComboBox1.addItem(makeObj("Muster 2"));
    jComboBox1.addItem(makeObj("Muster 3"));
    jComboBox1.addItem(makeObj("Muster 4"));
    jPanel7.add(jComboBox1, null);
    jPanel1.add(jPanel8, BorderLayout.CENTER);
    jPanel8.add(jTextArea1, BorderLayout.CENTER);
    jTabbedPane1.add(jPanel2, "Text anzeigen");
    jPanel2.add(jPanel4, BorderLayout.CENTER);
    jPanel4.add(jLabel1, BorderLayout.CENTER);
    jPanel4.add(jPanel6, BorderLayout.SOUTH);
    jPanel6.add(jCheckBox1, null);
    jPanel2.add(jPanel5, BorderLayout.NORTH);
    jPanel5.add(jToggleButton2, null);
      // Popup-Menü Eintrag hinzufügen
    jPopupMenu1.add(jMenuItem1);
      // Popup-Menü dem Panel hinzufügen
    jPanel3.add(jPopupMenu1);
  }
    // Methode zum Generieren von Objekten
    // Wird beim Erzeugen von Eintägen für das
    // Listenfeld verwendet
    private Object makeObj(final String item)  {
     return new Object() { public String toString() { return item; } };
    }
      // Reaktion auf Klicks im Listenfeld
  void jComboBox1_actionPerformed(ActionEvent e) {
      // Unterscheidung, welcher Eintrag 
      // ausgewählt wurde
  if(jComboBox1.getSelectedIndex()==0) {
  jTextArea1.setText("Es grünt so grün");
  }
  else if(jComboBox1.getSelectedIndex()==1) {
  jTextArea1.setText("Die Antwort ist 42");
  }
  else if(jComboBox1.getSelectedIndex()==2) {
  jTextArea1.setText("Wie denn, wo denn, was denn?");
  }
  else if(jComboBox1.getSelectedIndex()==3) {
  jTextArea1.setText("Was unterscheidet einen Porsche von einer Ente? Eine Ente ist 
cooler!");
  }
  }
  // Programm beenden
  void jToggleButton2_actionPerformed(ActionEvent e) {
  System.exit(0);
  }
  // Text aus TextArea übertragen in Label auf 
  // anderem Tabellenblatt - per Button
  void jToggleButton1_actionPerformed(ActionEvent e) {
  jLabel1.setText(jTextArea1.getText());
  }
  // Text aus TextArea übertragen in Label auf 
  // anderem Tabellenblatt - per Item im Popup
  void jMenuItem1_actionPerformed(ActionEvent e) {
  jLabel1.setText(jTextArea1.getText());
  }
  // Anzeigen Popup-Menü
  void jPanel3_mouseClicked(MouseEvent e) {
    // Nur wenn rechte Maustaste gedrückt
  if(e.getModifiers()==Event.META_MASK) {
    // Zeige Popup in angegebener Komponente
    // an den Koordinaten, wo Klick erfolgte
  jPopupMenu1.show(jPanel3,e.getX(),e.getY());
  }
  }
  // Checkbox ist selektiert oder nicht
  void jCheckBox1_actionPerformed(ActionEvent e) {
  if(jCheckBox1.isSelected()) {
  jLabel1.setVisible(true);
  }
  else  {
  jLabel1.setVisible(false);
  }
  }  }

Wenn das Programm gestartet wird, werden Sie zwei Registerblätter vorfinden. Auf dem zugrunde liegenden Container werden diverse weitere Panels und Komponenten platziert. Auf dem ersten Registerblatt werden Sie einen Button im oberen Bereich, im Zentrum ein vorbelegtes Texteingabefeld (multizeilenfähig, was über die Anweisung jTextArea1.setLineWrap(true) realisiert wird) und im unteren Bereich ein einzeiliges Listenfeld mit vorangestelltem Label finden.

Abbildung 11.21:  Das erste Registerblatt wird angezeigt.

Sowohl der Button als auch das per Klick mit der rechten Maustaste auf den Nordbereich ausgelöste Popup-Menü erlauben die Übertragung des Textes im Texteingabefeld an das Label im zweiten Registerblatt. Dabei istdie Erzeugung eines Popup-Menüs recht einfach. Ein vorher erzeugter Eintrag wird mit der üblichen add()-Methode hinzugefügt (jPopupMenu1.add- (jMenuItem1)) und das Popup-Menü dem Panel oder der Komponenten, auf der es agieren soll, hinzugefügt. In unserem Beispiel ist das das jPanel3 (jPanel3.add(jPopupMenu1)). Mit etwas größerem Aufwand verbunden ist die konkrete Methode, mit der auf Klicks des Popup-Menüs reagiert werden soll. Zwar kann recht unkompliziert die Übertragung des Textes aus der TextArea auf das Label auf dem anderem Tabellenblatt realisiert werden:

 void jMenuItem1_actionPerformed(ActionEvent e) {
  jLabel1.setText(jTextArea1.getText());
 }

Jedoch ist es etwas Mühe, das Menü nur beim Klick mit der rechten Maustaste anzuzeigen (standardmäßig wird es auch beim Klick mit der linken Maustaste aktiviert). Das lässt sich aber mit dem der aufgerufenen Methode übergebenen Event-Objekt steuern (ebenso die Koordinaten des Popups). Das Objekt enthält Informationen über die gedrückte Maustaste, die mit Klassenkonstanten von Event verglichen werden können:

  void jPanel3_mouseClicked(MouseEvent e) {
    // Nur wenn rechte Maustaste gedrückt
  if(e.getModifiers()==Event.META_MASK)  {
    // Zeige Popup in angegebener Komponente
    // an den Koordinaten, wo Klick erfolgte
  jPopupMenu1.show(jPanel3,e.getX(),e.getY());
  }
  }

Die Übertragung des Textes von dem Textfeld mit dem Button erfolgt recht einfach:

  void jToggleButton1_actionPerformed(ActionEvent e) {
  jLabel1.setText(jTextArea1.getText());
  }

Der Text im Eingabefeld kann frei geändert oder per Auswahl im unten stehenden Listenfeld vorgegeben werden. Das Listenfeld erhält seine Einträge über die Anweisungen der Form:

  jComboBox1.addItem(makeObj("Muster 1"));

Dabei erstellt die dort aufgerufene Methode makeObj() mit dem übergebenen String-Objekt über die Anweisungen

  return new Object() {
    public String toString() { 
    return item; 
   } 
  };

Die beim Klick auf das Listenfeld ausgelöste Reaktionsmethode void jComboBox1_actionPerformed(ActionEvent e) unterscheidet mit der Methode getSelectedIndex(), welcher Eintrag ausgewählt wurde:

  if(jComboBox1.getSelectedIndex()==0) {
  jTextArea1.setText("Es grünt so grün");
  }
  else if(jComboBox1.getSelectedIndex()==1) {
  jTextArea1.setText("Die Antwort ist 42");
  }
  else if(jComboBox1.getSelectedIndex()==2) {
  jTextArea1.setText("Wie denn, wo denn, was denn?");
  }
  else if(jComboBox1.getSelectedIndex()==3) {
  jTextArea1.setText("Was unterscheidet einen Porsche von einer Ente? Eine Ente ist 
cooler!");
  }
  }

Abbildung 11.22:  Das Popup-Menü

Auf dem zweiten Registerblatt wird der übernommene Text angezeigt, wenn die Checkbox entsprechend selektiert ist. Dazu gibt es die Anweisung jCheckBox1.setSelected(true), um die Checkbox beim Laden zu selektieren. Die Reaktionsmethode, ob die Checkbox selektiert ist oder nicht, sieht so aus:

  void jCheckBox1_actionPerformed(ActionEvent e) {
  if(jCheckBox1.isSelected()) {
  jLabel1.setVisible(true);
  }
  else {
  jLabel1.setVisible(false);
  }
  }

Der Ende-Button erlaubt den Abbruch des Programms.

Abbildung 11.23:  Das zweite Registerblatt und der übertragene Text werden angezeigt.

Ein Swing-Taschenrechner

Das abschließende Beispiel ist eine etwas komplexere Anwendung - ein Taschenrechner. Hier kommen - neben der doch etwas komplexeren Funktionalität - einige Beeinflussungen von Komponenteneigenschaften hinzu. Beachten Sie bitte die Kommentare im Quelltext, die die einzelnen Schritte ausführlich erläutern.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class TaschenrechnerPanel extends JPanel implements ActionListener { 
 private JTextField anzFeld;
 private double aktWerBer = 0;
 private String oprat = "=";
 private boolean begBer = true;
 public TaschenrechnerPanel() { 
// Definiere ein Borderlayout
 setLayout(new BorderLayout());
// Definiere anzFeld zur Ausgabe von 
// Tasteneingaben und berechnetem Ergebnis. Beim 
// Start soll es mit 0 vorbelegt sein. 
// Hintergrundfarbe ist default weiß,
// Ausrichtung rechtsbündig.
 anzFeld = new JTextField("0");
 anzFeld.setEditable(false);
 anzFeld.setHorizontalAlignment(
 JTextField.RIGHT);
 anzFeld.setBackground(java.awt.Color.white);
// Anzeige im Nordbereich des Borderlayouts (oben)
 add(anzFeld, "North");
// Definiere ein neues JPanel, das als 
// Subpanel dem Hauptpanel hinzugefügt wird. 
// Es soll die Buttons des Tastenfeldes beinhalten. 
// Das Layout in ein
// GridLayout mit 5 Zeilen und 4 Spalten.
 JPanel tastFeld = new JPanel();
 tastFeld.setLayout(new GridLayout(5, 4));
// Hinzufügen der einzelnen Schaltflächen mit 
// einer selbst definierten Methode.
// erste Reihe Tastenfeld
 fuegeBnHinzu(tastFeld, "C"); 
 fuegeBnHinzu(tastFeld, "F"); 
 fuegeBnHinzu(tastFeld, "Ende"); 
 fuegeBnHinzu(tastFeld, "%"); 
// zweite Reihe Tastenfeld
 fuegeBnHinzu(tastFeld, "7"); 
 fuegeBnHinzu(tastFeld, "8"); 
 fuegeBnHinzu(tastFeld, "9"); 
 fuegeBnHinzu(tastFeld, "/"); 
// dritte Reihe Tastenfeld
 fuegeBnHinzu(tastFeld, "4"); 
 fuegeBnHinzu(tastFeld, "5"); 
 fuegeBnHinzu(tastFeld, "6"); 
 fuegeBnHinzu(tastFeld, "*"); 
// vierte Reihe Tastenfeld
 fuegeBnHinzu(tastFeld, "1"); 
 fuegeBnHinzu(tastFeld, "2"); 
 fuegeBnHinzu(tastFeld, "3"); 
 fuegeBnHinzu(tastFeld, "-"); 
// fünfte Reihe Tastenfeld
 fuegeBnHinzu(tastFeld, "0"); 
 fuegeBnHinzu(tastFeld, "."); 
 fuegeBnHinzu(tastFeld, "="); 
 fuegeBnHinzu(tastFeld, "+"); 
// füge das Tastenfeld in den Haupt-Panel
 add(tastFeld, "Center");
 }
// Definition einer Methode, die einem 
// Container als Argument übergebene Schaltflächen 
// hinzufügt und beim ActionListener registriert.
 private void fuegeBnHinzu(Container uebergebenerContainer, String name) { 
// neuer Dummybutton
 JButton dummyButton = new JButton(name);
// Einfügen
 uebergebenerContainer.add(dummyButton);
// Registrieren
 dummyButton.addActionListener(this);
 }
// Die Aktionsreaktionsmethode 
 public void actionPerformed(ActionEvent evt) { 
 String eingTast = evt.getActionCommand();
// Bei Betätigen der Ende-Taste Taschenrecher 
// beenden
 if (eingTast == "Ende") System.exit(0);
// anzFeld auf 0 setzen, alle Operanden
// Zurücksetzen und Beginn der Berechnung 
// aktivieren
 if (eingTast == "C") {
 aktWerBer = 0;
 anzFeld.setText("" + aktWerBer);
 eingTast = "=";
 begBer = true;
 }
// anzFeld in der Farbe umsetzen
 if (eingTast == "F") {
 if (anzFeld.getBackground() == java.awt.Color.red) {
 anzFeld.setBackground(java.awt.Color.white);
 }
 else {
 anzFeld.setBackground(java.awt.Color.red);
 }
 }
// Die %-Taste wird anders als die sonstigen
// arithmetischen Operatoren behandelt. Grund: 
// nur ein vorangestellter Operand und nicht ein 
// dem Operator voran- und ein ihm nachgestellter 
// Operand.
 if (eingTast == "%") {
 aktWerBer = 
 Double.parseDouble(anzFeld.getText()) / 100;
 anzFeld.setText("" + aktWerBer);
 }
// Kontrolle, ob eine Zahl oder ein Dezimalpunkt 
// eingegeben wurde. Wenn ja, unterscheide, ob das
// Anzeigefeld bisher noch keinen Wert beinhaltet 
// bzw. ob eine neue Berechnung gestartet wird 
// oder ob sich im Anzeigefeld bereits ein Eintrag 
// befindet, der zur Berechnung verwendet werden 
// soll. Falls nicht, schreibe den Wert der 
// ausgelesenen Eingabe-Taste direkt in das 
// Anzeigefeld. Ansonsten hänge ihn an den 
// bisherigen Wert an.
 if ('0' <= eingTast.charAt(0) && eingTast.charAt(0) <= '9' || eingTast.equals(".")) { 
 if (begBer) anzFeld.setText(eingTast);
 else anzFeld.setText(anzFeld.getText() + eingTast);
 begBer = false;
 }
// Das eingegebene Zeichen war weder Zahl noch 
// Dezimalpunkt
 else { 
// Ein als erstes Zeichen eingegebenes Minus darf 
// nicht mit dem Start der Subtraktion verwechselt 
// werden, sondern wird dem Rechenoperanden 
// vorangestellt.
 if (begBer) { 
 if (eingTast.equals("-")) { 
 anzFeld.setText(eingTast); 
 begBer = false; 
 }
 else {
// erstes eingegebenes Zeichen ist ein Operator
 oprat = eingTast;
 }
 }
// Eingabe eines Operators (+, -, *, /)
 else { 
// Extrahiere einen double-Wert aus dem 
// Anzeigefeld
 double x = Double.parseDouble(anzFeld.getText());
// rufe Berechnungsmethode auf
 berechne(x);
 oprat = eingTast;
// neue Berechnung
 begBer = true;
 }   }   }
 public void berechne(double n) { 
 if (oprat.equals("+")) aktWerBer = aktWerBer + n;
 else if (oprat.equals("-")) aktWerBer = aktWerBer - n;
 else if (oprat.equals("*")) aktWerBer = aktWerBer * n;
 else if (oprat.equals("/")) aktWerBer = aktWerBer / n;
 else if (oprat.equals("=")) aktWerBer = n;
// Gebe Wert der Berechnung aus
 anzFeld.setText("" + aktWerBer);
 }  }
// Die Klasse, um ein Javafenster zu erzeugen
class TaschenrechnerFrame extends JFrame { 
// Konstruktor 
 public TaschenrechnerFrame() { 
 setTitle("Ein Swing-Taschenrechner");
 setSize(300, 320);
 addWindowListener(new WindowAdapter() { 
 public void windowClosing(WindowEvent e) { 
 System.exit(0);
 }
 } );
 getContentPane().add(new TaschenrechnerPanel());
 }  }
public class Taschenrechner { 
 public static void main(String[] args) { 
 JFrame javaFenster = new TaschenrechnerFrame();
 javaFenster.show(); 
 }  }

Abbildung 11.24:  Ein Swing-Taschenrechner

Wenn Sie die Tasten zu schnell bedienen (wirklich sehr schnell in einer ausreichend überlasteten Umgebung), kann es zu einem »Verschlucken« der Events kommen. Da im Eventmodell 1.1 nicht garantiert werden kann, in welcher Reihenfolge die Listener reagieren, kann das in Extremfällen zu einem Abarbeiten der Tastatureingaben in der falschen Reihenfolge führen. Ein solches Verhalten ist aber im Normalfall sehr unwahrscheinlich.

Von besonderer Bedeutung in dem Beispiel ist der WindowListener. Wenn Sie für eine eigenständige Swing-Applikation die Schnittstelle public abstract interface WindowListener extends EventListener in eine Klasse implementieren, muss die Klasse sieben Methoden implementieren:

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)

Von hauptsächlichem Interesse ist dabei die Methode windowClosing(), denn darin wird normalerweise die JVM heruntergefahren und das Programm beendet.

11.6 Zusammenfassung

Die Kommunikation mit dem Anwender wird in Java hauptsächlich über das AWT realisiert, aber Swing erweitert den Umfang erheblich. Dies betrifft einmal die Möglichkeit der Anpassung des Look and Feel an die zugrunde liegende Plattform bzw. an verschiedene Layouts, aber vor allem die Vielzahl an neuen Komponenten und Panels.

1

unverhältnismäßg langer Download des Plug-Ins, wenn es noch nicht vorhanden ist, Sicherheitsbedenken gegen ActiveX-Technologie, relativ komplexe Referenzierung


© Copyright Markt+Technik Verlag, ein Imprint der Pearson Education Deutschland GmbH
Elektronische Fassung des Titels: Java 2 Kompendium, ISBN: 3-8272-6039-6 Kapitel: 11 Swing & Co