MarktundTechnik Home-Page Previous Page TOC Index Next Page See Page



13. Tag:

Das Java Abstract Windowing Toolkit (AWT)

von Laura Lemay

In den letzten fünf Lektionen haben Sie sich auf das Schreiben von Applets konzentriert, die sehr einfache Dinge bewirken: Text anzeigen, eine Animation oder einen Sound abspielen und einige grundlegende Interaktionen mit dem Benutzer. An diesem Punkt angelangt, möchten Sie sicherlich etwas anspruchsvollere Applets entwickeln, die sich wie richtige Anwendungen verhalten und in eine Web-Seite eingebettet werden - Applets, die langsam aber sicher wie Anwendungen mit grafischen Benutzeroberflächen aussehen und Schaltflächen, Menüs, Textfelder und andere Elemente einer ausgewachsenen Anwendung aufweisen.

Für die Realisierung genau dieser Aspekte in Java-Applets und -Anwendungen wurde das Abstract Windowing Toolkit - kurz AWT - entwickelt. Sie haben die ganze Zeit über bereits das AWT benutzt, d. h. verschiedene Klassen daraus importiert. Die Applet-Klasse und die meisten Klassen, mit denen Sie diese Woche gearbeitet haben, sind Bestandteil des AWT. Der HotJava-Browser selbst wurde in Java unter Verwendung des AWT geschrieben.

Das AWT bietet folgendes:

Heute lernen Sie den Umgang mit all diesen Dingen in Java-Applets. Morgen lernen Sie das Erstellen von Fenstern, Menüs und Dialogfeldern, so daß Sie separate Fenster auf dem Browser-Fenster einblenden können. Darüber hinaus können Sie das AWT in Einzelanwendungen benutzen, wobei Sie alles, was Sie bisher in dieser Woche gelernt haben, wieder anwenden. Falls Sie den Rahmen des Web-Browsers zu begrenzt finden, können Sie den AWT-Hintergrund verwenden und ausgereifte Java-Anwendungen schreiben.

Vorläufig konzentrieren wir uns aber auch in der heutigen Lektion auf Applets.

Das ist die bisher bei weitem komplexeste Lektion. Wir müssen heute viel Lehrstoff abdecken und eine Menge Code durcharbeiten. Deshalb können Sie getrost für diese Lektion zwei Tage (oder mehr) einplanen.

AWT-Übersicht

AWT basiert auf dem Grundkonzept, daß ein Java-Fenster aus verschiedenen verschachtelten Komponenten besteht, beginnend vom äußersten Fenster bis zum kleinsten Element der Benutzeroberfläche. Diese Elemente bzw. Komponenten können Dinge beinhalten, die man am Bildschirm sieht, z. B. Fenster, Menüleisten, Schaltflächen und Textfelder, sie können aber auch sogenannte »Container« enthalten, die ihrerseits andere Komponenten enthalten. Abb. 13.1 zeigt eine Beispielseite eines Java-Browsers mit verschiedenen Komponenten, die alle über das AWT verwaltet werden.

Diese Verschachtelung von Komponenten in Containern innerhalb von anderen Komponenten bildet eine Hierarchie von Komponenten, vom kleinsten Kontrollfeld in einem Applet bis zum Hauptfenster am Bildschirm. Die Komponentenhierarchie bestimmt die Anordnung von Elementen am Bildschirm und innerhalb anderer Elemente, die Reihenfolge, in der sie erscheinen, und wie Ereignisse zwischen Komponenten weitergegeben werden.

Abbildung 13.1: AWT-Komponenten

Die wichtigsten Komponenten, mit denen Sie im AWT arbeiten können, sind:

Die Klassen im java.awt-Paket wurden so geschrieben und organisiert, daß sie die abstrakte Struktur von Containern, Komponenten und einzelnen Elementen einer Benutzeroberfläche abbilden. Abb. 13.2 zeigt einen Teil der Klassenhierarchie mit den wichtigsten AWT-Klassen. Die Wurzel der meisten AWT-Komponenten ist die Klasse Component, die grundlegende Anzeige- und Ereignishandhabungsfunktionen bereitstellt. Die Klassen Container, Canvas, TextComponent und viele andere Klassen für Benutzeroberflächen erben von Component. Durch Vererbung von der Container-Klasse können Objekte andere AWT-Komponenten, insbesondere die Klassen Panel und Window, enthalten. Die java.applet.Applet-Klasse lebt zwar in einem eigenen Paket, erbt aber von Panel, so daß Ihre Applets Bestandteil der Komponentenhierarchie des AWT-Systems werden.

Abbildung 13.2: Hauptteil der AWT-Klassenhierarchie

Eine Anwendung mit einer grafischen Benutzeroberfläche, die Sie unter Verwendung des AWT schreiben, kann so komplex sein wie Sie nur wollen, mit Dutzenden von verschachtelten Containern und Komponenten. AWT wurde so ausgelegt, daß jede Komponente ihren Part im globalen AWT-System spielen kann, ohne dupliziert werden oder das Verhalten anderer Systemteile übernehmen zu müssen.

Basiskomponenten für die Benutzeroberfläche

Die einfachste Form von AWT-Komponenten sind Basiskomponenten für die Benutzeroberfläche. Sie können diese Komponenten in Ihr Applet einfügen, ohne etwas über das Erstellen von Containern oder Panels wissen zu müssen. Noch bevor Sie beginnen, etwas zu zeichnen und Ereignisse zu definieren, ist Ihr Applet bereits ein AWT-Container. Anders ausgedrückt, ist jedes Applet von Geburt an ein Container. Aus diesem Grund können Sie andere AWT-Komponenten, z. B. für die Benutzeroberfläche oder weitere Container, in Ihr Applet stellen.

In diesem Abschnitt lernen Sie, mit den Basiskomponenten für die Benutzeroberfläche - Label, Schaltflächen, Kontrollfelder, Auswahlmenüs und Textfelder - zu arbeiten. In jedem Fall ist die Prozedur zum Erstellen der Komponente gleich: Sie erstellen zuerst die Komponente, dann fügen Sie sie in das Panel ein, so daß sie am Bildschirm angezeigt wird. Um eine Komponente (z. B. Ihr Applet) in ein Panel zu stellen, verwenden Sie die add()-Methode:

public void init() {

   Button b = new Button("OK");

   add(b);

}

Wo die Komponenten im Panel erscheinen, hängt von dem für das Panel definierten Layout ab. Das Standardlayout für Panels wie Applets ist FlowLayout. Das ist ein Layout mit zentrierter Ausrichtung, was bedeutet, daß die Komponenten mittig angeordnet werden. Dies erklärt, warum einige Beispiele in diesem Abschnitt ein bißchen seltsam aussehen. Sie lernen im diesem Abschnitt mehr über Panels und Layouts.

Jede dieser Komponenten ist mit einer Aktion verbunden, d. h. etwas, das die Komponente tut, wenn sie aktiviert wird. Aktionen lösen im allgemeinen Ereignisse oder andere Aktivitäten (die man in anderen Window-Toolkits »Callbacks« nennt) im Applet aus. Wir konzentrieren uns in diesem Lektionsteil auf das Erstellen von Komponenten. Wie Aktionen hinzugefügt werden, lernen Sie später in dieser Lektion.

Stürzen wir uns also auf Komponenten!

Label

Ein Label ist die einfachste Form einer Komponente für Benutzeroberflächen.

Label sind Textketten, die benutzt werden, um andere Komponenten der Benutzeroberfläche zu beschriften.

Ein Label weist im Vergleich zu normalen Textketten den Vorteil auf, daß es das Layout des jeweiligen Panels einhält und daß Sie es nicht jedesmal nachzeichnen müssen, wenn das Panel neu gezeichnet wird. Label können auch leicht in einem Panel ausgerichtet werden. Das bedeutet, daß Sie andere Komponenten der Benutzeroberfläche mit einem Label beschriften können, ohne deren genaue Pixelpositionen zu wissen.

Sie verwenden folgende Constructors, um ein Label zu erstellen:

Ein Label erhält standardmäßig den globalen Font für die Komponente (der in der setFont()-Methode definiert wurde).

Mit dem folgenden einfachen Code werden ein paar Labels erstellt. Wie sie am Bildschirm aussehen, ist in Abb. 13.3 ersichtlich:

add(new Label)"aligned left "));

add(new Label("aligned center", Label.center));

add(new Label("aligned right", Label.right));

Abbildung 13.3: Verschiedene Label

Nachdem Sie ein Label-Objekt erstellt haben, können Sie Methoden aus der Label-Klasse verwenden, um Werte für den Text zu holen und zu setzen (siehe Tabelle 13.1).

Methode Aktion
getText() Gibt eine Zeichenkette für den Label-Text aus.
setText(String) Ändert den Label-Text.
getAlignment() Gibt eine Ganzzahl aus, die die Label-Ausrichtung darstellt:
0 = Label.LEFT, 1 = Label.CENTER, 2 = Label.RIGHT
setAlignment(int) Ändert die Ausrichtung des Labels auf die angegebene Ganzzahl oder Klassenvariable ab.
Tabelle 13.1: Label-Methoden

Schaltflächen

Als zweite Komponente für Benutzeroberflächen erforschen wir Schaltflächen.

Schaltflächen (Buttons) sind einzelne Elemente einer grafischen Benutzeroberfläche, die durch Anklicken die bezeichnete Aktion ausführen. Übliche Schaltflächen in einem Dialogfeld sind beispielsweise »OK« und »Abbrechen«.

Um eine Schaltfläche zu erstellen, benutzen Sie einen der folgenden Constructors:

Nachdem Sie ein Schaltflächenobjekt erstellt haben, können Sie den Wert für seine Beschriftung mit der getLabel()-Methode holen und die Beschriftung mit den setLabel(String)-Methoden setzen.

In Abb. 13.4 sehen Sie ein paar einfache Schaltflächen, die mit folgendem Code erstellt wurden:

add(new Button("Rewind"));

add(new Button("Play"));

add(new Button("Fast Forward"));

add(new Button("Stop"));

Abbildung 13.4: Schaltflächen

Kontrollfelder

Kontrollfelder enthalten Optionen, die ein- und ausgeschaltet werden können.

Kontrollfelder sind Komponenten einer grafischen Benutzeroberfläche, die ein- oder ausgeschaltet werden, also einen von zwei Stati haben können (true oder false). Ausgewählte Optionen in einem Kontrollfeld sind mit einem X gekennzeichnet. Je nach Bedarf können mehrere Kontrollfeldoptionen ausgewählt werden.

Kontrollfelder können auf zwei Arten benutzt werden:

Kontrollfelder für sich nicht gegenseitig ausschließende Optionen werden mit der Checkbox-Klasse erstellt. Sie können ein Kontrollfeld auch mit einem der folgenden Constructors erstellen:

In Tabelle 13.2 werden die Methoden für Kontrollfelder aufgeführt. Abb. 13.5 zeigt ein paar einfache Kontrollfelder (nur Underwear ist gewählt), die mit folgendem Code erstellt wurden:

add(new Checkbox("Shoes"));

add(new Checkbox("Socks"));

add(new Checkbox("Pants"));

add(new Checkbox("Underwear", null, true));

add(new Checkbox("Shirt"));

Abbildung 13.5: Kontrollfelder

Optionsfelder

Optionsfelder sind eine Variante von Kontrollfeldern.

Optionsfelder (Radio Buttons) sehen genauso aus wie Kontrollfelder, jedoch kann jeweils nur eine Option gewählt werden, d. h. sie enthalten sich gegenseitig ausschließende Optionen.

Um Optionsfelder zu erstellen, legen Sie zuerst eine Instanz von CheckboxGroup an:

CheckboxGroup cbg = new CheckboxGroup();

Dann erstellen Sie die einzelnen Optionsfelder und fügen sie in die Gruppe ein, indem Sie die Gruppe als zweites Argument benutzen. Ferner bestimmen Sie, ob ein Optionsfeld gewählt ist oder nicht (es kann jeweils nur eine Option gewählt werden):

add(new Checkbox("Yes", cbg, true));

add(new Checkbox("No", cbg, false));

Der folgende einfache Beispielcode ergibt die in Abb. 13.6 dargestellte Optionsfeldergruppe:

CheckboxGroup cbg = new CheckboxGroup();

add(new Checkbox("Red", cbg, true));

add(new Checkbox("Blue", cbg, false));

add(new Checkbox("Yellow", cbg, false));

add(new Checkbox("Green", cbg, false));

add(new Checkbox("Orange", cbg, false));

add(new Checkbox("Purple", cbg, false));

Abbildung 13.6: Optionsfeld

Alle im vorherigen Abschnitt definierten Kontrollfeldmethoden können mit den Optionsfeldern in der Gruppe benutzt werden. Darüber hinaus können Sie die Methoden getCheckboxGroup() und setCheckboxGroup() anwenden, um auf die Gruppe eines Kontrollfeldes zuzugreifen und sie zu ändern.

Schließlich können die in der Optionsfeldergruppe definierten Methoden getCurrent() und setCurrent(Checkbox) benutzt werden, um das momentan ausgewählte Optionsfeld zu holen und zu setzen.

Auswahlmenüs

Auswahlmenüs sind komplexere Komponenten einer Benutzeroberfläche als Label, Schaltflächen und Kontrollfelder.

Auswahlmenüs sind Popup- oder Pulldown-Menüs, die sich beim Anklikken öffnen und mehrere Optionen anzeigen, aus denen eine ausgewählt werden kann.

Um ein Auswahlmenü zu erstellen, legen Sie eine Instanz der Choice-Klasse an und benutzen die addItem()-Methode, um einzelne Optionen in der Reihenfolge, in der sie angezeigt werden sollen, einzufügen:

Choice c = new Choice();

c.addItem("Apples");

c.addItem("Oranges");

c.addItem("Strawberries");

c.addItem("Blueberries");

c.addItem("Bananas");

Schließlich fügen Sie das gesamte Auswahlmenü auf die übliche Weise in das Panel ein:

add(c);

Abb. 13.7 zeigt ein einfaches Auswahlmenü, das mit dem obigen Code erstellt wurde.

Abbildung 13.7: Auswahlmenü

In einem Auswahlmenü kann nur jeweils eine Option gewählt werden. Soll die Auswahl mehrerer Optionen ermöglicht werden, benutzen Sie statt dessen Listenfelder.

Nachdem Sie ein Auswahlmenü erstellt haben, können Sie mit dem Hinzufügen von Optionen zu diesem Menü mit der addItem()-Methode fortfahren, ungeachtet dessen, ob Sie das Auswahlmenü bereits in ein Panel eingefügt haben. In Tabelle 13.3 stehen einige weitere Methoden, die im Zusammenhang mit Auswahlmenüs nützlich sind.

Methode Aktion
getItem(int) Gibt die Zeichenkette des Elements an der angegebenen Stelle aus (Elemente in einem Auswahlmenü beginnen bei 0, wie bei Arrays).
countItems() Gibt die Anzahl der im Menü enthaltenen Elemente aus.
getSelectedIndex() Gibt die Indexposition des ausgewählten Elements aus.
getSelectedItem() Gibt das momentan ausgewählte Element als Zeichenkette aus.
select(int) Wählt das Element an der angegebenen Stelle.
select(String) Wählt das Element mit der angegebenen Zeichenkette.
Tabelle 13.2: Methoden für Auswahlmenüs

Textfelder

Im Gegensatz zu den bisher beschriebenen Komponenten für Benutzeroberflächen, bei denen aus mehreren Optionen eine ausgewählt oder eine Aktion ausgeführt werden kann, ermöglichen Textfelder die Eingabe von Werten.

Ein Textfeld ist ein umrandeter Bereich in einem Fenster oder Dialogfeld, in das Daten eingegeben werden können.

Um ein Textfeld zu erstellen, benutzen Sie einen der folgenden Constructors:

Folgender Beispielcode erzeugt ein Textfeld mit einer Breite von 30 Zeichen und der Zeichenkette »Enter Your Name« als Anfangsinhalt, der überschrieben werden kann.

TextField tf = new TextField("Enter Your Name",30);

add(tf);

Textfelder beinhalten nur das editierbare Feld. Sie müssen in der Regel eine Beschriftung (Label) in ein Textfeld einbeziehen, um anzugeben, was in das Textfeld eingegeben werden soll oder kann.

Textfelder unterscheiden sich von Textbereichen dadurch, daß ihre Größe begrenzt ist und idealerweise nur für einzeilige Elemente verwendet wird. Demgegenüber haben Textbereiche Bildlaufleisten und eignen sich besser für größere Textfenster. Beide Arten können mit der Maus angesteuert und editiert werden. Sie lernen Textbereiche noch in der heutigen Lektion.

Sie können die in einem Textfeld stehenden Zeichen auch verbergen bzw. durch Ersatzzeichen darstellen, z. B. bei Paßwortfeldern. Hierfür erstellen Sie zuerst das Textfeld, dann verwenden Sie die setEchoCharacter()-Methode, um das zu verbergende Zeichen am Bildschirm zu setzen. Hier ein Beispiel:

textField tf = new TextField(30);

tf.setEchoCharacter('*');

In Abb. 13.8 sehen Sie drei Textfelder (und Label), die mit folgendem Code erstellt wurden:

add(new Label("Enter your Name"));

add(new TextField("your name here2,45));

add(new Label("Enter your phone number"));

add(new TextField(12));

add(new Label("Enter your password"));

Textfield t = new TextField(20);

t.setEchoCharacter('*');

add(t);

Abbildung 13.8: Textfelder

Textfelder erben von der Klasse TextComponent und haben eine ganze Reihe von Methoden, die sowohl von dieser Klasse geerbt als auch in einer eigenen Klasse definiert sind. Sie sind nützlich für alle Arten von Java-Programmen. Tabelle 13.4 enthält eine Auswahl dieser Methoden.

Methode Aktion
getText() Gibt den Text des Feldes (als Zeichenkette) aus.
setText(String) Setzt die angegebene Zeichenkette in das Feld.
getColumns() Gibt die Breite des Textfeldes aus.
select(int, int) Wählt den Text zwischen den zwei ganzzahligen Positionen (Positionen beginnen bei 0).
selectAll() Wählt den gesamten Text im Feld aus.
isEditable() Gibt true oder false aus, je nach dem, ob der Text editierbar ist.
setEditable(boolean) Definiert, ob der Text im Feld editiert werden kann (true = Standard) oder unveränderlich ist (false).
getEchoChar() Gibt das Ersatzzeichen für das eingegebene Zeichen aus.
echoCharIsSet() Gibt true oder false aus, je nach dem, ob das Feld mit einem Ersatzzeichen belegt ist.
Tabelle 13.3: Methoden für Textfelder

Panels und Layout

Sie wissen bereits, daß ein AWT-Panel Komponenten der Benutzeroberfläche oder andere Panels enthalten kann. Die Frage lautet, wie diese Komponenten angeordnet und am Bildschirm angezeigt werden.

In anderen Fenstersystemen werden Komponenten der Benutzeroberfläche meist anhand von hartcodierten Pixelmaßen angeordnet, z. B. Textfeld tf auf 10,30, ebenso wie Sie Grafikoperationen benutzen, um Vierecke und Ovale am Bildschirm auszugeben. Im AWT kann das Fenster in vielen verschiedenen Fenstersystemen auf unterschiedlichen Bildschirmen und mit verschiedenen Fonts angezeigt werden. Deshalb brauchen wir flexiblere Methoden, um Komponenten so am Bildschirm anordnen zu können, daß das Layout auf jeder Plattform gut aussieht.

Für diesen Zweck hat Java verschiedene Layout-Manager, Einsätze und Tips für jede Komponente. Das Angenehme an AWT-Komponenten und Elementen der Benutzeroberfläche ist, daß Sie sie nicht zeichnen müssen. Das wird vom AWT-System übernommen. Verwenden Sie grafische Komponenten oder Bilder, oder möchten Sie Animationen in Panels erstellen, müssen Sie das manuell realisieren. Bei den meisten Basiskomponenten übernimmt jedoch Java die gesamte Arbeit; Sie brauchen sie nur in den Bildschirm zu stellen.

Layout-Manager

Das Aussehen der AWT-Komponenten am Bildschirm wird von zwei Aspekten bestimmt: Der Reihenfolge, in der sie im Panel eingefügt und angeordnet werden, und dem Layout-Manager, den das Panel für das Layout am Bildschirm nutzt. Der Layout-Manager bestimmt, wie Bildschirmbereiche aufgeteilt und Komponenten des Panels angeordnet werden.

Jedes Panel am Bildschirm kann einen eigenen Layout-Manager haben. Durch Verschachteln von Panels innerhalb von Panels und Verwendung des entsprechenden Layout-Managers für jedes Panel können Sie Ihre Benutzeroberfläche funktionell und attraktiv für unterschiedliche Fenstersysteme und Plattformen auslegen. Wie Panels verschachtelt werden, lernen Sie in einem späteren Lektionsteil.

Das AWT beinhaltet vier Layout-Manager: FlowLayout, GridLayout, BorderLayout und CardLayout. Um einen Layout-Manager für ein bestimmtes Panel zu erstellen, verwenden Sie die setLayout()-Methode:

public void init() {

   this.setLayout(new FlowLayout());

}

Das Setzen des Layout-Standardmanagers und das Definieren der Komponenten der Benutzeroberfläche sind Operationen, die vorzugsweise in die Initialisierung des Applets bzw. der Klasse eingebunden werden.

Danach werden die Komponenten in das Panel eingefügt. Die Reihenfolge, in der die Komponenten hinzugefügt werden, ist meist wichtig, je nach dem, welcher Layout-Manager jeweils aktiv ist. Lesen Sie die Informationen über den jeweiligen Layout-Manager durch und wie die entsprechenden Komponenten im Panel eingerichtet werden.

In den folgenden Abschnitten werden die vier Layout-Manager von Java-AWT beschrieben.

Die FlowLayout-Klasse

Die FlowLayout-Klasse beinhaltet das einfachste Layout. Mit diesem Layout werden die Komponenten nacheinander zeilenweise in das Panel eingefügt. Paßt eine Komponente nicht in eine Zeile, wird sie automatisch auf die nächste Zeile umgebrochen. Das Flußlayout hat eine Ausrichtung, die die Ausrichtung aller Zeilen vorgibt. Standardmäßig ist jede Zeile zentriert. Abb. 13.9 zeigt ein typisches Flußlayout - eine Reihe von Schaltflächen, die in einer Zeile zentriert sind.

Abbildung 13.9: Flußlayout

Um ein einfaches Flußlayout mit zentrierter Ausrichtung zu erstellen, schreiben Sie in der Panel-Initialisierung folgende Codezeile:

setLayout(new FlowLayout());

Um ein Flußlayout mit einer rechten oder linken Ausrichtung zu erstellen, fügen Sie die Klassenvariable flowLayout.right oder FlowLayout.left als Argument ein:

setLayout(new FlowLayout(FlowLayout.left));

Anhand von Flußlayouts können Sie auch horizontale und vertikale Abstandswerte setzen. Der Abstand ist die Zahl der Pixel zwischen Komponenten in einem Panel. Standardmäßig sind die horizontalen und vertikalen Abstandswerte drei Pixel, was sehr eng ist. Der horizontale Abstand ist links und rechts zwischen Komponenten, der vertikale oben und unten. Um den Abstand zu erhöhen, fügen Sie in den Flußlayout-Constructor ganzzahlige Argumente ein (Abb. 13.10 zeigt einen Layoutabstand von 10 Punkten in horizontaler und vertikaler Richtung):

setLayout(new FlowLayout(FlowLayout.left),10,10);

Abbildung 13.10: Flußlayout mit einem Abstand von 10 Punkten in horizontaler und vertikaler Richtung

Die GridLayout-Klasse

Rasterlayouts bieten mehr Kontrolle über die Anordnung von Komponenten in einem Panel. Mit einem Rasterlayout können Sie den Panel-Bereich in Zeilen und Spalten aufteilen. Jede Komponente, die Sie dann in das Panel einfügen, wird in einer »Zelle« des Rasters von links oben nach rechts unten in das Raster eingefügt (hier ist die Reihenfolge relevant, in der die add()-Methode aufgerufen wird). Durch Verwendung von Rasterlayouts und verschachtelten Rastern erreichen Sie meist annähernd die Wirkung hartcodierter Pixelwerte, um Komponenten auf der Benutzeroberfläche genau an der gewünschten Stelle anzuordnen. Abb. 13.11 zeigt ein Rasterlayout mit drei Spalten und zwei Zeilen.

Abbildung 13.11: Rasterlayout

Um ein Rasterlayout zu erstellen, geben Sie die Anzahl der gewünschten Zeilen und Spalten in einer neuen Instanz der GridLayout-Klasse an:

setLayout(new GridLayout(3,3));

Auch bei Rasterlayouts können Sie den horizontalen und vertikalen Abstand zwischen den Komponenten bestimmen. Hierfür fügen Sie die entsprechenden Pixelwerte ein:

setLayout(new GridLayout(3,3,10,15));

In Abb. 13.12 sehen Sie das Rasterlayout von Abb. 13.11, jedoch mit einem horizontalen Abstand von 10 und einem vertikalen von 15 Pixel.

Eine Variante von Rasterlayouts bietet die GridBagLayout-Klasse. Mit diesen Layouts können Sie Elemente der Benutzeroberfläche auch in einem rechteckigen Raster auslegen, haben aber viel mehr Kontrolle über die Darstellung der einzelnen Elemente im Raster. Für diese Varianten von Rasterlayouts gibt es die Hilfsklasse GridBagConstraints, mit der bezeichnet werden kann, wie jede einzelne Zelle im Raster zu formatieren ist.

Die Klassen GridBagLayout und GridBagConstraints wurden in das Java Developer's Kit erst kurz vor Drucklegung dieses Buches eingefügt. Eine umfassendere Beschreibung dieser Layouts finden Sie in der API-Dokumentation zu diesen Klassen.

Abbildung 13.12: Rasterlayout mit größerem horizontalen und vertikalen Abstand

Die BorderLayout-Klasse

Rahmenlayouts verhalten sich anders als Fluß- und Rasterlayouts. Wenn Sie eine Komponente in ein Panel einfügen, das auf einem Rahmenlayout basiert, müssen Sie die Anordnung als geographische Richtung angeben: Nord, Süd, Ost, West und Mitte (siehe Abb. 13.13). Die Komponenten rund um die Kanten werden in der benötigten Größe ausgelegt. Falls es eine Komponente in der Mitte gibt, erhält sie den restlichen Platz zugeteilt.

Abbildung 13.13: Rahmenlayout

Um ein Rahmenlayout zu erstellen, verfahren Sie wie bei den anderen Layouts:

setLayout(new BorderLayout());

Dann fügen Sie die einzelnen Komponenten mit einer speziellen add()-Methode ein: Das erste Argument für add() ist eine Zeichenkette, die die Position der Komponente im Layout bezeichnet:

add("North", new TextField("Title",50));

add("south", new TextField("Status",50));

Sie können diese Form von add() auch für andere Layout-Manager verwenden. Das Argument für die Zeichenkette wird einfach ignoriert, falls es nicht benötigt wird.

Auch bei Rahmenlayouts sind horizontale und vertikale Abstände möglich. Beachten Sie, daß sich die Nord- und Südkomponenten über die gesamte Kante des Panels erstrecken, so daß der Abstand auf Kosten des Platzes für die Komponenten in Ost, West und Mitte entsteht. Um Abstände in ein Rahmenlayout einzufügen, tragen Sie die entsprechenden Pixelwerte wie bei den anderen Layouts ein:

setLayout(new BorderLayout(10,10));

Die CardLayout-Klasse

Kartenlayouts unterscheiden sich von den anderen Layoutarten. Im Gegensatz zu den drei oben beschriebenen Layouts werden beim Kartenlayout nicht alle Komponenten, die Sie eingefügt haben, gleichzeitig am Bildschirm angezeigt. Kartenlayouts werden verwendet, um eine Art Diaschau der Komponenten zu erzeugen. Falls Sie je mit HyperCard auf dem Macintosh gearbeitet haben, kennen Sie das Prinzip von Kartenlayouts.

Im allgemeinen werden die Komponenten, die Sie beim Erstellen eines Kartenlayouts einfügen, als weitere Container - normalerweise Panels - behandelt. Sie können für die einzelnen »Karten« je ein anderes Layout verwenden, so daß jeder Bildschirm anders aussieht.

Jede »Karte«, die Sie in das Panel einfügen, wird benannt. Nachdem Sie für die einzelnen Karten einen Namen vergeben haben, können Sie die in der CardLayout-Klasse definierten Methoden anwenden, um in den Karten im Layout vorwärts und rückwärts zu blättern.

Mit dem folgenden Code wird beispielsweise ein Kartenlayout mit drei Karten erstellt:

setLayout(new CardLayout());

Panel one = new Panel();

add("first", one);

Panel two = new Panel();

add("second", two);

Panel three = new Panel();

add("third", three);

show(this, "second");

Eckeinsätze

Während horizontale und vertikale Abstände dazu dienen, den Platz zwischen einzelnen Komponenten in einem Panel festzulegen, wird mit Eckeinsätzen des Randes um das Panel bestimmt. Die Klasse für Eckeinsätze bietet Werte für Einrückungen oben, unten, links und rechts, die dann verwendet werden, wenn das Panel gezeichnet wird. In Abb. 13.14 sehen Sie ein Beispiel mit Eckeinsätzen in einem Rasterlayout.

Abbildung 13.14: Rasterlayout mit Eckeinsätzen

Um einen Eckeinsatz einzufügen, überschreiben Sie die insets()-Methode in Ihrer Klasse (Ihre Applet-Klasse oder eine andere Klasse, die als Panel dient):

public Insets insets() {

   return new Insets(10,10,10,10);

}

Die Argumente für den Eckeinsatz-Constructor enthalten die einzurückenden Pixel, d. h. den oberen, unteren, linken und rechten Rand des Panels. Das hier aufgezeigte Beispiel hat einen Eckeinsatz von 10 Pixel auf allen vier Seiten des Panels.

Aktionen und Ereignisse der Benutzeroberfläche

Falls Sie mit dem Bearbeiten der heutigen Lektion an dieser Stelle aufgehört haben, verfügen Sie über das Wissen, um ein Applet zu erstellen, das viele kleine Komponenten der Benutzeroberfläche enthält, mit dem entsprechenden Layout-Manager ansprechend am Bildschirm ausgelegt ist sowie Abstände und Eckeinsätze hat. Ihr Applet wäre allerdings ziemlich fade, weil die Komponenten der Benutzeroberfläche eigentlich nichts tun, wenn man sie anklickt oder die entsprechende Taste drückt.

Damit Ihre Komponenten der Benutzeroberfläche etwas bewirken, wenn sie aktiviert werden, müssen Sie sie mit der entsprechenden Aktion verknüpfen.

Das Testen auf eine Aktion einer Komponente der Benutzeroberfläche ist eine Form des Ereignismanagements - die Dinge, die Sie gestern über Ereignisse gelernt haben. Hier können Sie das alles praktisch anwenden. Insbesondere erzeugen Komponenten der Benutzeroberfläche eine spezielle Ereignisart, die wir Aktion nennen. Damit eine Komponente der Benutzeroberfläche eine Aktion ausführen kann, müssen Sie in Ihrem Applet bzw. in der Klasse eine action()-Methode definieren:

public boolean action(Event evt, Object arg) {

   ...

}

Die action()-Methode dürfte angesichts der bereits gelernten grundlegenden Ereignismethoden für Maus und Tastatur vertraut aussehen. Wie jene Methoden wird sie an das Event-Objekt, das das jeweilige Ereignis darstellt, weitergegeben. Außerdem erhält sie ein zusätzliches Objekt, das ein beliebiger Typ sein kann. Wozu brauchen wir hier ein zweites Argument?

Das zweite Argument für die Aktionsmethode hängt von der Komponente der Benutzeroberfläche ab, durch die das Ereignis erzeugt wird. Die Basisdefinition ist ein arbiträres Argument, das, wenn eine Komponente ein Ereignis erzeugt, zusätzliche Informationen abgeben kann, die später gebraucht werden. Da diese zusätzlichen Informationen für Sie nützlich sein können, leiten Sie sie durch die action()-Methode weiter.

Alle grundlegenden Komponenten der Benutzeroberfläche (ausgenommen Label) haben unterschiedliche Aktionen und Argumente:

Im Gegensatz zu gewöhnlichen Ereignissen, z. B. einem Einzelereignis wie mouseDown, können bei Aktionen viele verschiedene Objektarten das Ereignis auslösen. Um diese verschiedenen Komponenten der Benutzeroberfläche und die von ihnen erzeugten Aktionen zu handhaben, müssen Sie den Objekttyp testen, der das Ereignis im Körper der action()-Methode aufruft. Dieses Objekt wird in der target-Instanzvariablen des Ereignisses gespeichert. Sie können den instanceof-Operator benutzen, um herauszufinden, von welcher Komponente das Ereignis ausgeht:

public boolean action(Event evt, Object arg) {

   if (evt.target instanceof TextField)

      handleText(evt.target);

   else if (evt.target instanceof Choice)

      handleChoice(arg);

...

}

Sie können Aktionen der Benutzeroberfläche zwar im Körper der action()-Methode handhaben, jedoch ist es meist einfacher, eine Handler-Methode zu definieren und diese Methode statt dessen in action() aufzurufen. Hier haben wir zwei Handler-Methoden: Eine zur Handhabung der Aktion des Textfeldes (handleText()) und eine für die Aktion des Auswahlmenüs (handleChoice()). Je nach Aktion müssen Sie eventuell das Argument der Aktion oder andere Informationen, die das Ereignis enthält, weitergeben.

Das folgende einfache Applet hat fünf beschriftete Schaltflächen mit Farben. Die action()-Methode testet auf eine Schaltflächenaktion und gibt sie an die Methode changeColor() weiter, die die Hintergrundfarbe des Applets ändert, je nach dem, welche Schaltfläche gedrückt wurde (siehe Abb. 13.15):

import java.awt.*;

public class ButtonActionsTest extends java.applet.Applet {

   public void init() {

      setBackground(Color.white);

      add(new Button("Red"));

      add(new Button("Blue"));

      add(new Button("Green"));

      add(new Button("White"));

      add(new Button("Black"));

   }

   public boolean action(Event evt, Object arg) {

      if (evt.target instanceof Button)

         changeColor((String)arg);

      return true;

   }

   void changeColor(String bname) {

      if (bname.equals("Red")) setBackground(Color.red);

      else if (bname.equals("Blue")) setBackground(Color.blue);

      else if (bname.equals("Green")) setBackground(Color.green);

      else if (bname.equals ("White")) setBackground(Color.white);

      else setBackground(Color.black);

   }

}

Abbildung 13.15: Das ButtonAction-Applet

Verschachteln von Panels und Komponenten

Durch Hinzufügen von Komponenten der Benutzeroberfläche kommt Leben in Ihr Applet. Richtig interessant wird es aber, wenn Sie mit verschachtelten Panels arbeiten. Durch Verschachteln mehrerer Panels in einem Applet und mehrerer Panels in Panels können Sie verschiedene Layouts für unterschiedliche Teile des Applet-Bereichs erstellen, Hinter- und Vordergrundfarben und Fonts auf einzelne Applet-Teile begrenzen und das Design der Komponenten Ihrer Benutzeroberfläche sauberer und einfacher auslegen. Je komplexer das Layout Ihres Applets ist, um so mehr bietet sich das Verschachteln von Panela an.

Verschachtelte Panela

Wie Sie bereits wissen, sind Panels Komponenten, die am Bildschirm angezeigt werden können. Container aus der Superklasse Panel bietet die allgemeinen Eigenschaften zum Anlegen weiterer Komponenten. Die Applet-Klasse, von der alle Ihre Applets erben, ist eine Subklasse von Panel. Um andere Panels in einem Applet zu verschachteln, erstellen Sie ein neues Panel und fügen es in das Applet ein:

setLayout(new GridLayout(1,2,10,10));

Panel panel1 = new Panel();

Panel panel2 = new Panel();

add(panel1);

add(panel2);

Sie können dann für diese untergeordneten Panels ein unabhängiges Layout wählen und AWT-Komponenten (und weitere untergeordnete Panels) einfügen, indem Sie die add()-Methode im entsprechenden Panel aufrufen:

panel1.setLayout(new FlowLayout());

panel1.add(new Button("Up"));

panel1.add(new Button("Down"));

Dies können Sie zwar alles in einer Klasse realisieren, jedoch ist es bei Applets üblich, starken Gebrauch von Panels zu machen, um das Layout und Verhalten der untergeordneten Panels in separaten Klassen anzulegen und die Panels durch Verwendung von Methodenaufrufen miteinander kommunizieren zu lassen. Später in der heutigen Lektion betrachten Sie noch ein umfangreiches Beispiel.

Ereignisse und verschachtelte Panels

Bei einem Applet mit verschachtelten Panels bilden die Panels eine Hierarchie vom äußersten Panel (normalerweise dem Applet) bis zur innersten Komponente der Benutzeroberfläche. Diese Hierarchie ist wichtig für die Art, wie die einzelnen Komponenten im Applet miteinander oder mit dem Browser interagieren. Insbesondere bestimmt die Komponentenhierarchie die Reihenfolge, in der die Komponenten am Bildschirm ausgegeben werden.

Vor allem aber wirkt sich diese Hierarchie auf die Ereignishandhabung aus, insbesondere auf Ereignisse, die durch Benutzereingaben aktiviert werden, z. B. Maus- und Tastaturereignisse.

Ereignisse werden von der innersten Komponente in der Hierarchie entgegengenommen und in der Kette bis zur Wurzel weitergereicht. Nehmen wir beispielsweise an, Sie haben ein Applet mit einem untergeordneten Panel, das Mausereignisse abwickelt (mit den Methoden mouseDown() und mouseUp()) und daß das Panel eine Schaltfläche enthält. Durch Anklicken der Schaltfläche erhält die Schaltfläche das Ereignis, bevor es das Panel erreicht. Ist die Schaltfläche nicht an mouseDown() interessiert, wird das Ereignis an das Panel weitergeleitet, das den Vorgang dann verarbeitet oder seinerseits in der Hierarchie weitergibt.

Sie erinnern sich an die gestrige Diskussion über die grundlegenden Ereignismethoden? Sie haben gelernt, daß alle Ereignismethoden boolesche Werte ausgeben. Diese booleschen Werte sind im Zusammenhang mit der Handhabung oder Weitergabe von Ereignissen wichtig.

Eine Ereignishandhabungsmethode kann auf drei Arten reagieren, ob es sich um eine grundlegende Ereignismethode oder handleEvent() handelt:

Verschiedene Komponenten der Benutzeroberfläche

Nachdem Sie gelernt haben, wie die grundlegenden Komponenten der Benutzeroberfläche funktionieren, wie sie in Panels eingefügt und wie ihre Ereignisse gehandhabt werden, können Sie weitere Komponenten hinzufügen. Sie lernen in diesem Abschnitt das Arbeiten mit Textbereichen, Auswahllisten, Bildlaufleisten und Zeichenbereichen.

Die in diesem Abschnitt beschriebenen Komponenten bewirken keine Aktionen, deshalb können Sie die action()-Methode nicht verwenden, um ihr Verhalten zu steuern. Statt dessen benutzen Sie die handleEvent()-Methode, um auf spezifische Ereignisse, die von diesen Komponenten erzeugt werden, zu testen. Im nächsten Abschnitt lernen Sie mehr darüber.

Textbereiche

Textbereiche unterscheiden sich von Textfeldern dadurch, daß sie mehr Funktionalität zur Handhabung größerer Textmengen bieten. Da die Größe von Textfeldern begrenzt ist und Textfelder nicht gerollt werden können, eignen sie sich besser für einzeilige Eingaben. Textbereiche können eine beliebige Breite und Höhe haben. Standardmäßig haben sie auch Bildlaufleisten, so daß größere Textmengen leicht untergebracht werden können.

Um einen Textbereich zu erstellen, verwenden Sie einen der folgenden Constructors:

Abb. 13.16 zeigt einen einfachen Textbereich, der mit folgendem Code erzeugt wurde:

String str = "Once upon a midnight dreary, while I pondered, weak and weary,\n" +

   "Over many a quaint and curious volume of forgotten lore,\n" +

   "while I nodded, nearly napping, suddenly there came a tapping,\n" +

   "As of some one gently rapping, rapping at my chamber door.\n" +

   "\"'Tis some visitor,\" I muttered, \"tapping at my chamber door-\n";

add(new TextArea(str,10,60));

Abbildung 13.16: Textbereich

Sowohl Textbereiche als auch Textfelder erben von der TextComponent-Klasse, deshalb ist ein Großteil des Verhaltens von Textfeldern (insbesondere Text und Auswahl holen und einrichten) auch auf Textbereiche anwendbar (siehe Tabelle 13.4). Darüber hinaus gibt es für Textbereiche spezielle Methoden. Eine Auswahl dieser Methoden ist in Tabelle 3.5 aufgeführt.

Methode Aktion
getColumns() Gibt die Breite des Textbereichs in Zeichen oder Spalten aus.
getRows() Gibt die Länge des Textbereichs in Zeilen aus (entspricht nicht der Anzahl der im Bereich enthaltenen Textzeilen).
insertText(String, int) Fügt an der angegebenen Position eine Zeichenkette in den Text ein (Textpositionen beginnen bei 0).
replaceText
(String, int, int)
Ersetzt den Text zwischen den angegebenen ganzzahligen Positionen durch eine andere Zeichenkette.
Tabelle 13.4: Methoden für Textbereiche

Listenfelder

Erinnern Sie sich an das Auswahlmenü, in dem mehrere Optionen zur Wahl angeboten werden? Ein Listenfeld hat eine ähnliche Funktionalität, da wie in einem Auswahlmenü auch verschiedene Optionen in einer Liste ausgewählt werden können. Listenfelder unterscheiden sich von Auswahlmenüs durch folgende Aspekte:

Um ein Listenfeld zu erstellen, legen Sie eine Instanz der List-Klasse an und fügen die einzelnen Einträge in die Liste ein. Die List-Klasse hat zwei Constructors:

Nachdem Sie ein List-Objekt erstellt haben, fügen Sie mit der addItem()-Methode Einträge ein und stellen dann die Liste in das betreffende Panel. Der folgende Beispielcode ergibt das in Abb. 13.17 dargestellte Listenfeld:

List lst = new List(5, true);

lst.addItem("Hamlet");

lst.addItem("Claudius");

lst.addItem("Gertrude");

lst.addItem("Polonius");

lst.addItem("Horatio");

lst.addItem("Laertes");

lst.addItem("Ophelia");

add(lst);

Abbildung 13.17: Beispiel eines Listenfeldes

In Tabelle 13.6 sind einige Methoden aufgeführt, die für Listenfelder verfügbar sind. Eine vollständige Aufstellung der Methoden für Listenfelder finden Sie in der API-Dokumentation.

Methode Aktion
getItem(int) Gibt die Zeichenkette des Eintrags an der angegebenen Position aus.
countItems() Gibt die Anzahl der Einträge in der Liste aus.
getSelectedIndex() Gibt die Indexposition des ausgewählten Eintrags aus (dient für Listen mit sich gegenseitig ausschließenden Optionen).
getSelectedIndexes() Gibt eine Reihe von Indexpositionen aus (dient für Listen, in denen mehrere Optionen ausgewählt werden können).
getSelectedItem() Gibt den momentan ausgewählten Eintrag als Zeichenkette aus.
getSelectedItems() Gibt eine Reihe von Zeichenketten aus, die ausgewählte Einträge enthalten.
select(int) Wählt den Eintrag in der bezeichneten Position.
select(String) Wählt den Eintrag mit dieser Zeichenkette.
Tabelle 13.5: Methoden für Listenfelder

Bildlaufleisten und Schieber

Textbereiche und Listenfelder haben eigene Bildlaufleisten, die in diesen Komponenten der Benutzerfläche bereits integriert sind und dem Benutzer ermöglichen, den Textbereich oder die Liste zu rollen, um weitere Einträge anzuzeigen. Sie können aber auch einzelne Bildlaufleisten bzw. Schieber erstellen, um einen Wertbereich zu manipulieren.

Bildlaufleisten dienen zur Auswahl eines Wertes zwischen einem Höchst- und einem Mindestwert. Um den aktuellen Wert einer Bildlaufleiste zu ändern, können Sie drei verschiedene Teile der Bildlaufleiste benutzen (siehe Abb. 13.18):

Abbildung 13.18: Teile einer Bildlaufleiste

Durch Auswahl dieser visuellen Elemente wird der Wert in der Bildlaufleiste geändert. Sie brauchen nichts zu aktualisieren und auch keine Ereignisse zu verwalten. Nötig ist nur die Festlegung eines Höchst- und Mindestwertes für die Bildlaufleiste. Der Rest wird von Java erledigt.

Um eine Bildlaufleiste zu erstellen, benutzen Sie einen dieser drei Constructors:

Das erste Argument ist die Ausrichtung der Bildlaufleiste: Scrollbar.horizontal oder Scrollbar.vertical.

Das zweite Argument ist der Anfangswert der Bildlaufleiste, der ein Wert zwischen dem Höchst- und Mindestwert der Bildlaufleiste sein sollte.

Das dritte Argument ist die Gesamtbreite (bzw. Höhe, je nach Ausrichtung) der Box der Bildlaufleiste. Im Benutzeroberflächendesign impliziert eine größere Box, daß jeweils ein größerer Anteil des Gesamtbereichs angezeigt wird (eignet sich am besten für Fenster und Textbereiche).

Das vierte und fünfte Argument bezeichnet den Mindest- bzw. Höchstwert der Bildlaufleiste.

Mit dem folgenden einfachen Code wird eine Bildlaufleiste erstellt, die sich um je einen einzelnen Wert erhöht (siehe Abb. 13.19). Das Label links neben der Bildlaufleiste wird jedesmal, wenn sich der Wert der Bildlaufleiste ändert, aktualisiert:

import java.awt.*;

public class SliderTest extends java.applet.Applet {

   Label 1;

   public void init() {

      1 = new Label("0");

      add(1);

      add(new Scrollbar(Scrollbar.horizontal, 1, 0, 1, 100));

   }

   public boolean handleEvent(Event evt) {

      if (evt.target instanceof Scrollbar) {

         int v = ((Scrollbar)evt.target).getValue();

         l.setText(String.valueOf(v));

      }

      return true;

   }

}

Abbildung 13.19: Beispiel einer Bildlaufleiste

Die Scrollbar-Klasse bietet mehrere Methoden zum Handhaben der Werte in einer Bildlaufleiste (siehe Abb. 13.7).

Methode Aktion
getMaximum() Gibt den Höchstwert aus.
getMinimum() Gibt den Mindestwert aus.
getOrientation() Bestimmt die Ausrichtung der Bildlaufleiste 0 = vertikal,
1 = horizontal.
getValue() Gibt den aktuellen Wert der Bildlaufleiste aus.
setValue(int) Setzt den aktuellen Wert der Bildlaufleiste.
Tabelle 13.6: Methoden für Bildlaufleisten

Zeichenbereiche

Sie können zwar auf den meisten AWT-Komponenten, z. B. Paneln, zeichnen, jedoch sind Zeichenbereiche speziell zum Zeichnen da. Zeichenbereiche können keine anderen Komponenten enthalten, akzeptieren aber Ereignisse. Außerdem können Sie Animationen und Bilder in Zeichenbereichen anzeigen. Mit anderen Worten, Zeichenbereiche sollten speziell für Zeichnungen und Grafiken verwendet werden.

Ein Zeichenbereich ist eine Komponente, auf der gezeichnet werden kann.

Um einen Zeichenbereich zu erstellen, benutzen Sie die Canvas-Klasse und fügen sie genau wie andere Komponenten in ein Panel ein:

Canvas can = new Canvas();


add(can);

Verschiedene Ereignisse der Benutzeroberfläche

Gestern haben Sie einige grundlegende Ereignisarten gelernt, die durch Benutzereingaben mit der Maus oder Tastatur erzeugt werden. Diese Ereignisarten werden im Event-Objekt als Ereignis-ID gespeichert und können im Körper einer handleEvent()-Methode mit den in Event definierten Klassenvariablen getestet werden. Für viele Basisereignisse, z. B. mouseDown() und keyDown(), können Sie Methoden definieren, um das jeweilige Ereignis direkt zu handhaben. Einen ähnlichen Mechanismus haben Sie heute für Aktionen der Benutzeroberfläche gelernt, wobei eine action()-Methode erstellt wird, um eine spezifische, von einer Komponente der Benutzeroberfläche erzeugte Aktion abzuarbeiten.

Die allgemeingültige Art der Handhabung von Ereignissen ist immer die handleEvent()-Methode. Ereignisse im Zusammenhang mit Bildlaufleisten und Listenfeldern können nur durch Überschreiben von handleEvent() realisiert werden.

Um ein spezifisches Ereignis zu realisieren, testen Sie die ID dieses Ereignisses. Die verfügbaren IDs sind als Klassenvariablen in der Event-Klasse definiert, so daß Sie sie nach Namen testen können. Einige Basisereignisse haben Sie bereits gestern gelernt. Tabelle 13.7 enthält weitere Ereignisse, die für die Komponenten, die Sie heute gelernt haben, nützlich sind (oder die Sie allgemein nützlich finden).

Methode Aktion
getMaximum() Gibt den Höchstwert aus.
ACTION_EVENT Wird erzeugt, wenn eine Aktion einer Komponente der Benutzeroberfläche stattfindet.
KEY_ACTION Wird erzeugt, wenn eine Aktion eines Textfeldes stattfindet.
LIST_DESELECT Wird erzeugt, wenn ein Eintrag in einem Listenfeld abgewählt wird.
LIST_SELECT Wird erzeugt, wenn ein Eintrag in einem Listenfeld gewählt wird.
SCROLL_ABSOLUTE Wird erzeugt, wenn die Box einer Bildlaufleiste verschoben wird.
SCROLL_LINE_DOWN Wird erzeugt, wenn der untere (oder linke) Endpunkt einer Bildlaufleiste gewählt wird.
SCROLL_LINE_UP Wird erzeugt, wenn der obere (oder rechte) Endpunkt einer Bildlaufleiste gewählt wird.
SCROLL_PAGE_DOWN Wird erzeugt, wenn das Feld unterhalb (oder links neben) der Box der Bildlaufleiste gewählt wird.
SCROLL_PAGE_UP Wird erzeugt, wenn das Feld oberhalb (oder rechts neben) der Box der Bildlaufleiste gewählt wird.
Tabelle 13.7: Auswahl weiterer Ereignisse

Komplettes Beispiel: RGB/HSB-Konverter

Wir haben bisher viel Theorie und kleinere Beispiele durchgearbeitet und wenden uns nun einem größeren Beispiel zu, in dem die bisher gelernten Teile zusammengesetzt werden. Das folgende Applet enthält Layouts, verschachtelte Panel, Komponenten der Benutzeroberfläche und Aktionen. Ferner werden in dem Beispiel mehrere Klassen zu einem einzelnen Applet zusammengestellt. Kurz: Sie bearbeiten hier das bisher komplexeste Applet.

Abb. 13.20 zeigt das Applet, das Sie in diesem Beispiel schreiben. Das ColorTest-Applet ermöglicht die Auswahl von Farben auf der Grundlage von RGB- (Rot, Grün und Blau) und HSB-Werten (Farbton, Sättigung und Helligkeit).

Abbildung 13.20: Das ColorTest-Applet

Das ColorTest-Applet hat drei Hauptteile: eine Farbbox auf der linken Seite und zwei Gruppen mit Textfeldern auf der rechten Seite. Die erste Feldergruppe zeigt die RGB-Werrte, die rechte die HSB-Werte an. Durch Ändern der Werte in einem der Textfelder wird die Farbbox links aktualisiert, so daß jeweils die Farbe angezeigt wird, die in den Feldern gewählt wurde.

Das Applet nutzt zwei Klassen:

Wir arbeiten nun das Applet schrittweise durch, weil es kompliziert ist und leicht verwirren kann. Am Ende dieser Lektion steht der gesamte Code dieses Applets.

Erstellen des Applet-Layouts

Die beste Art, mit einem Applet zu beginnen, das AWT-Komponenten beinhaltet, ist das Festlegen des Layouts. Dabei sollten Sie mit dem äußersten Panel beginnen und sich nach innen durcharbeiten.

Sie können sich die Arbeit vereinfachen, indem Sie alle Panels Ihres Benutzeroberflächendesigns zuerst auf Papier aufzeichnen, um die Fläche des Applets bzw. des Bildschirms optimal zu nutzen. Abb. 13.21 zeigt das ColorTest-Applet mit einem Raster, damit Sie einen Einblick darüber erhalten, wie die Panels ausgelegt und eingebettet werden.

Abbildung 13.21: Die Panel und Komponenten des ColorTest-Applets

Erstellen des Panel-Layouts

Wir beginnen mit dem äußersten Panel - das ist das Applet selbst. Dieses Panel hat drei Teile: Die Farbbox links, die RGB-Textfelder in der Mitte und die HSB-Felder rechts.

Da es sich um das Applet handelt, benutzen Sie die ColorTest-Klasse als Applet-Klasse, die von Applet erbt. Außerdem importieren Sie hier die AWT-Klassen (da wir in diesem Programm viele davon benutzen, importieren wir kurzerhand das gesamte Paket):

import java.awt.*;

public class ColorTest extends java.applet.Applet {

...

}

Wir fahren mit der init()-Methode fort, in der die gesamte Initialisierung und das Layout stehen. Sie arbeiten in vier Schritten:

1.   Sie setzen das Layout für die großen Teile des Panels. Ein Flußlayout wäre zwar möglich, jedoch eignet sich ein Rasterlayout mit einer Zeile und drei Spalten besser.

2.   Sie erstellen die drei Komponenten des Applets: Einen Zeichenbereich für die Farbbox und zwei untergeordnete Panels für die Textfelder.

3.   Sie fügen diese Komponenten in das Applet ein.

4.   Sie initialisieren die Standardfarbe und aktualisieren alle Panels auf diese Standardfarbe.

Bevor Sie mit diesen Schritten beginnen, richten Sie für die drei wichtigen Komponenten des Applets Instanzvariablen ein. Sie müssen diese Objekte verfolgen, damit beim Ändern von Werten entsprechend aktualisiert werden kann.

Die Farbbox ist einfach - lediglich ein Zeichenbereich. Rufen Sie ihn mit swatch auf.

Canvas swatch;

Jetzt folgen die untergeordneten Panels. Davon gibt es zwei, die zwar unterschiedliche Beschriftungen und Werte haben, jedoch im Grunde gleich sind. Sie könnten für die zwei Panels je einen eigenen Code schreiben, würden dadurch aber viel duplizieren. Das ist eine gute Gelegenheit, eine andere Klasse zu erstellen, die die untergeordneten Panels mit den Textfeldern darstellt. Rufen Sie sie mit ColorControls auf (diese Klasse erstellen Sie später noch) und definieren Sie die zwei Variablen RGBcontrols und HSBcontrols:

ColorControls RGBcontrols, HSBcontrols;

Wieder zurück zur init()-Methode. Der erste Schritt ist das Layout. Verwenden Sie ein Rasterlayout und setzen Sie einen Abstand von zehn Punkten zwischen den Komponenten:

setLayout(new GridLayout(1,3,10,10));

Im zweiten Schritt erstellen Sie die Komponenten, beginnend mit dem Zeichenbereich. Sie haben bereits eine Instanzvariable dafür:

swatch = new Canvas();

Sie müssen zwei Instanzen Ihrer bisher noch nicht existierenden ColorControls-Panels erstellen, wissen aber nicht genau, was Sie dafür brauchen. Deshalb fügen Sie ein paar grundlegende Constructors ein und tragen die Einzelheiten später nach:

RGBcontrols = new ColorControls()

HSBcontrols = new ColorControls();

Im dritten Schritt fügen Sie sie in das Panel ein:

add(swatch);

add(RGBcontrols);

add(HSBcontrols);

Da Sie ohnehin gerade an einem Layout arbeiten, fügen Sie als zusätzliche Spielerei einen Eckeinsatz ein - zehn Punkte an allen Kanten:

public Insets insets() {

   return new Insets(10,10,10,10);

}

Haben Sie das alles? Dann haben Sie eine skelettartige init()-Methode und eine insets()-Methode in Ihrer ColorTest-Klasse. Als nächstes fahren Sie mit dem Erstellen des Layouts für die untergeordneten Panels fort, d. h. Sie erstellen die ColorControls-Klasse.

Definieren der untergeordneten Panels

Die ColorControls-Klasse enthält das Verhalten für das Layout und die Handhabung der untergeordneten Panels für die RGB- und HSB-Werte. ColorControls muß keine Subklasse von Applet sein, weil es sich nicht um ein Applet, sondern nur um ein Panel handelt. Definieren Sie sie so, daß sie von Panel erbt:

class ColorControls extends Panel {

   ...

}

Sie können die ColorControls-Klasse in die gleiche Datei stellen wie die ColorTest-Klasse. Das haben Sie bisher nicht gemacht, weil die Applets und Anwendungen, die Sie bisher geschrieben haben, nur eine Klasse hatten. Am 1. Tag haben Sie gelernt, daß in einer Datei mehrere Klassendefinitionen abgelegt werden können, solange eine dieser Definitionen public deklariert wird. In diesem Fall ist die ColorTest-Klasse public (das muß sein, weil es ein Applet ist). Bei der ColorControls-Klasse ist das nicht nötig, also können beide in einer Datei sein.

Sie brauchen in dieser Klasse mehrere Instanzvariablen. Zuerst müssen Sie wieder zur Applet-Klasse, die dieses Panel enthält, zurückverzweigen. Warum? Da die Applet-Klasse darüber wacht, wie die untergeordneten Komponenten arbeiten, ist das die Klasse, die alles aktualisiert. Dann müssen Sie eine Methode in dieser Klasse aufrufen, um zu bezeichnen, daß sich etwas in diesem Panel geändert hat. Ohne Referenz auf diese äußere Klasse besteht hierfür keine Möglichkeit. Somit ist die erste Instanzvariable eine Referenz auf die Klasse ColorTest:

ColorTest outerparent;

Da die Applet-Klasse für das Aktualisieren aller Änderungen zuständig ist, braucht diese Klasse eine Möglichkeit, der einzelnen Teile habhaft zu werden. Insbesondere ist sie an den Textfeldern interessiert, deshalb brauchen Sie Instanzvariablen, die diese Felder aufnehmen. Sie erstellen drei:

TextField f1, f2, f3;

Jetzt geht's an den Constructor für diese Klasse. Wiederum handelt es sich nicht um ein Applet, deshalb verwenden Sie nicht init(). Sie brauchen lediglich eine Constructor-Methode.

Was wird in den Constructor gestellt? Sie müssen das Layout für das untergeordnete Panel festlegen, die Textfelder erstellen und sie in das Panel einfügen. Das Ziel ist hier, die ColorControls-Klasse so allgemein auszulegen, daß Sie sie für die RGB- und die HSB-Felder verwenden können.

Die zwei Panels unterscheiden sich durch zwei Aspekte: die Beschriftung und die Anfangswerte der Textfelder. Das sind sechs Werte, die berücksichtigt werden müssen, bevor Sie das Objekt erstellen. Sie können diese sechs Werte durch die Constructors in ColorTest weitergeben. Dann brauchen Sie noch einen Wert. Da Sie auf die Applet-Klasse zurückverzweigen müssen, geben Sie als Teil des Constructors auch eine Referenz auf dieses Objekt weiter.

Damit haben Sie für den Constructor der ColorControls-Klasse sieben Argumente. Die Unterschrift für diesen Constructor sieht so aus:

ColorControls(ColorTest target,

   String l1, String l2, String l3,

   int v1, int v2, int v3) {

}

Mit diesen Argumenten können Sie Ihren Instanzvariablen die richtigen Werte zuweisen:

outerparent = target;

f1 = new TextField(String.valueOf(v1),10);

f2 = new TextField(String.valueOf(v2),10);

f3 = new TextField(String.valueOf(v3),10);

Da das erste Argument für den TextField-Constructor eine Zeichenkette ist und die an sie abgegebenen Werte Ganzzahlen sind, müssen Sie die (in String definierte) valueOf()-Methode verwenden, um die Ganzzahlen vor dem Erstellen der Textfelder in Zeichenketten umzuwandeln.

Als nächstes erstellen Sie das Layout für dieses Panel. Sie verwenden für die untergeordneten Panels ebenfalls ein Rasterlayout, wie für das Applet-Panel, jedoch diesmal mit drei Zeilen (je eine für die Textfeld- und die Beschriftungspaare) und zwei Spalten (eine für die Beschriftungen und eine für die Felder).

In dieses 3-zu-2-Raster können Sie jetzt die Textfelder und Beschriftungen für das Panel einfügen. Durch Trennen der Beschriftungen und Textfelder in zwei Rasterzellen können Sie die Beschriftungen attraktiv ausrichten.

add(new Label(11, Label.right));

add(f1);

add(new Label(12, Label.right));

add(f2);

add(new Label(13, Label.right));

add(f3);

Weil mir Eckeinsätze so gut gefallen, rücken Sie den Inhalt des untergeordneten Panels ein bißchen ein - nur die obere und untere Kante. Sie verwenden dafür die insets()-Methode:

public Insets insets() {

   return new Insets(10,10,0,0);

}

Sie haben es fast schon geschafft. 98% des Layouts sind fertig, es fehlen aber noch zwei Dinge: die ColorControls-Objekte in ColorTest müssen noch erstellt und alles muß initialisiert werden, damit alle Komponenten die richtigen Werte erhalten.

Für beide Arbeiten müssen Sie zur ColorTest-Klasse und der darin definierten init()-Methode zurückkehren. Sie beginnen mit der Initialisierung, weil das leicht ist. Die Standardfarbe ist Schwarz. Richten Sie eine lokale Variable für dieses Farbobjekt ein:

Color theColor = new Color(0,0,0);

Zum Setzen der Anfangsfarbe für die Farbbox brauchen Sie nur den Hintergrund zu definieren:

swatch.setBackground(theColor);

Jetzt werden diese untergeordneten Panels initialisiert. Der Constructor von ColorControls hat sieben Argumente: das ColorTest-Objekt, drei Beschriftungen (Zeichenketten) und drei Anfangswerte für die Textfelder (Ganzzahlen). Sie beginnen mit den RGB-Feldern, weil sich die Grundfarben Rot, Grün und Blau leicht aus dem Color-Objekt herausziehen lassen:

RGBcontrols = new ColorControls(this, "Red", "Green", "Blue",

   theColor.getRed(), theColor.getGreen();

   theColor.getBlue());

Die HSB-Seite des Panels ist etwas schwieriger. Die Color-Klasse bietet eine Methode, die HSB-Werte aus einem Color-Objekt herauszuziehen, jedoch gibt es zwei Schwierigkeiten:

Die Initialisierung des HSB-Panels ist nicht ganz einfach.

Zuerst ziehen wir die HSB-Werte heraus. Da diese Methode drei RGB-Werte - eine Reihe von drei Gleitpunktwerten - hat und eine solche Reihe ausgibt, müssen Sie den ganzen Prozeß des Holens dieser Werte durchlaufen:

float[] HSB = Color.RGBtoHSB(theColor.getRed(),

   theColor.getGreen(), theColor.getBlue(),(new float[3]));

Jetzt haben Sie eine Reihe von Gleitpunktwerten, wobei HSB[0] der Farbton (Hue), HSB[1] die Sättigung (Saturation) und HSB[2] die Helligkeit (Brightness) ist. Sie können jetzt die HSB-Seite des Applets (endlich!) initialisieren. Stellen Sie sicher, daß Sie diese HSB-Werte bei der Weitergabe an das Panel mit den richtigen Werten multiplizieren (360 für den Farbton, 100 für die Sättigung und Helligkeit) und sie in Ganzzahlen konvertieren:

HSBcontrols = new ColorControls(this,

   "Hue", "Saturation", "Brightness",

   (int) (HSB[0] * 360), (int) (HSB[1] * 100),

   (int) (HSB[2] * 100));

Werfen Sie die Flinte nicht ins Korn, Sie haben den schwierigen Teil bereits hinter sich gebracht. Ab hier ist (fast) alles einfach. Sie haben ein funktionierendes Layout und können nun Ihr Java-Programm kompilieren, um zu sehen, wie es aussieht. Ihre Komponenten der Benutzeroberfläche bewirken noch nichts, aber die Perfektionierung des Layouts ist bei einem solchen Applet das A und O.

Handhabung der Aktionen

Nachdem Sie das Layout erstellt und geprüft haben, richten Sie die Aktionen für die Komponenten der Benutzeroberfläche ein, damit das Applet auf die Benutzereingaben reagieren kann.

Die Aktion findet bei diesem Applet statt, wenn der Benutzer in einem der Textfelder einen Wert ändert. Durch Anwenden einer Aktion auf ein Textfeld ändert sich die Farbe, die Farbbox wird auf diese Farbe aktualisiert und die Werte der Felder im gegenüberliegenden Panel ändern sich auf die neu eingestellte Farbe ab.

Für die Aktualisierung ist die ColorTest-Klasse zuständig, weil sie alle Panels verwaltet. Die Ereignisse im Panel müssen verfolgt und erfaßt werden. Da es sich bei der Aktion dieses Applets um eine Textaktion handelt, können Sie dafür eine action()-Methode verwenden:

public boolean action(Event evt, Object arg) {

   if (evt.target instanceof TextField) {

      this.outerparent.update(this);

      return true;

   }

   else return false;

}

Sie testen nun die action()-Methode, um sicherzustellen, daß die Aktion tatsächlich von einem Textfeld ausgelöst wurde (da nur Textfelder verfügbar sind, erhalten Sie nur diese Aktion, jedoch ist das Testen trotzdem ratsam). Dann rufen Sie die in ColorTest definierte update()-Methode auf, um das Applet auf die neuen Werte fortzuschreiben. Da das äußere Applet für die gesamte Fortschreibung zuständig ist, müssen Sie genau an dieser Stelle auf das Applet verzweigen, damit Sie die richtige Methode zum richtigen Zeitpunkt aufrufen können.

Aktualisieren des Ergebnisses

Das Aktualisieren der Werte beim Ändern der Farbe durch den Benutzer ist alles, was noch zu tun bleibt. Hierfür definieren Sie die update()-Methode in der ColorTest-Klasse. Diese update()-Methode hat ein Argument - die ColorControls-Instanz, die den geänderten Wert enthält (Sie holen dieses Argument aus der action()-Methode des untergeordneten Panels).

Fürchten Sie nicht, daß diese update()-Methode die gleichnamige Methode des Systems stört. Sie tut es nicht, denn wie Sie sich erinnern, können Methoden den gleichen Namen, jedoch unterschiedliche Unterschriften und Definitionen haben. Da diese update()-Methode nur ein Argument vom Typ ColorControls hat, beeinflußt sie nicht die übrigen update()-Versionen.

Die update()-Methode ist für das Aktualisieren aller Panels des Applets zuständig. Um zu wissen, welches Panel zu aktualisieren ist, müssen Sie wissen, welches Panel geändert wurde. Sie finden das heraus, indem Sie testen, ob das abgegebene Argument mit den untergeordneten Panels, die Sie in den Instanzvariablen RGBcontrols und HSBcontrols gespeichert haben, identisch ist:

void update(ColorControls in) {

   if (in == RGBcontrols) { // Änderung in RGB

      ---

   }

   else { // Änderung in HSB

}

Dieser Test ist der Kern der update()-Methode. Sie beginnen mit diesem ersten Fall - einer Zahl, die in den RGB-Textfeldern geändert wurde. Anhand dieser neuen RGB-Werte müssen Sie ein neues Farbobjekt erstellen und die Werte im HSB-Panel aktualisieren. Damit Sie nicht so viel tippen müssen, erstellen Sie ein paar lokale Variablen, in die Sie einige Grundwerte stellen. Die Werte der Textfelder sind Zeichenketten, auf die Sie durch die Textfeld-Instanzvariablen des ColorControls-Panels (f1,f2,f3) zugreifen. Dann benutzen Sie die getText()-Methode, um die eigentlichen Werte herauszuziehen. Diese Werte speichern Sie in Zeichenkettenvariablen:

String v1 = in.f1.getText();

String v2 = in.f2.getText();

String v3 = in.f3.getText();

Nun erstellen Sie ein Farbobjekt, indem Sie die Zeichenketten für die RGB-Werte in Ganzzahlen umwandeln:

Color c;

c = new Color(Integer.parseInt(v1),Integer.parseInt(v2),

   Integer.parseInt(v3));

Dieser Teil des Beispiels ist nicht sehr robust. Er basiert auf der Annahme, daß der Benutzer nichts anderes als Zahlen in die Textfelder eingibt. Eine bessere Version wäre ein Test, mit dem sichergestellt wird, daß keine Analysefehler passieren. (Ich wollte das Beispiel absichtlich kurz halten.)

Mit einem Farbobjekt können Sie die Farbe aktualisieren:

swatch.setBackground(c);

Im nächsten Schritt wird das HSB-Panel auf die neuen HSB-Werte aktualisiert. Das alles muß in der init()-Methode erfolgen, was hier nicht so einfach ist. Sie rufen RGBtoHSB auf, um die Gleitpunktwerte zu holen. Dann konvertieren Sie sie in die richtigen Ganzzahlen, wandeln diese wieder in Zeichenketten um und stellen sie in die Textfelder des HSB-Panels zurück. Hier ist der Code:

float[] HSB = Color.RGBtoHSB(c.getRed(),c.getGreen(),

   c.getBlue(), (new float[3]));

HSB[0] *= 360;

HSB[1] *= 100;

HSB[2] *= 100;

HSBcontrols.f1.setText(String.valueOf((int)HSB[0]));

HSBcontrols.f2.setText(String.valueOf((int)HSB[1]));

HSBcontrols.f3.setText(String.valueOf((int)HSB[2]));

Der zweite Teil der update()-Methode wird aufgerufen, wenn ein Wert auf der HSB-Seite des Panels geändert wird. Das ist »else« in der »if-else«-Klausel, die je nach Änderung bestimmt, was zu aktualisieren ist.

Ob Sie's glauben oder nicht, die RGB-Werte sind auf der Grundlage der HSB-Werte einfacher zu aktualisieren als umgekehrt. Zuerst konvertieren Sie die Zeichenkettenwerte der HSB-Textfelder durch folgende Codezeilen in Ganzzahlen:

int f1 = Integer.parseInt(v1);

int f2 = Integer.parseInt(v2);

int f3 = Integer.parseInt(v3);

In der Color-Klasse gibt es eine Methode, die ein neues Farbobjekt erstellt, wenn sie drei HSB-Werte erhält. Diese Werte sind vom Typ float und entsprechen nicht den aktuellen Werten. Um getHSBColor() (das ist der Name dieser Methode) aufzurufen, konvertieren Sie die Ganzzahlen in float und dividieren das Ergebnis durch die richtigen Zahlen:

c = Color.getHSBColor((float)f1 / 360, (float)f2 / 100, (float)f3/100);

Nun haben Sie ein Farbobjekt und setzen die Farbe:

swatch.setBackground(c);

Dann aktualisieren Sie die RGB-Textfelder auf die neuen RGB-Werte aus dem Farbobjekt:

RGBcontrols.f1.setText(String.valueOf(c.getRed()));

RGBcontrols.f2.setText(String.valueOf(c.getGreen()));

RGBcontrols.f3.setText(String.valueOf(c.getBlue()));

Der komplette Quellcode

Listing 13.1 enthält den vollständigen Quellcode. Meist ist es anhand eines kompletten Codes einfacher, sich vorzustellen, was in einem Applet abläuft, als wenn einzelne Teile des Codes getrennt betrachtet werden.

Listing 13.1: Das ColorTest-Applet

import java.awt.*;

public class ColorTest extends java.applet.Applet {

   ColorControls RgBcontrols, HSBcontrols;

   Canvas swatch;



   public void init() {

      Color theColor = new Color(0,0,0);

      float[] HSB = Color.rGBtoHSB(theColor.getRed(),

         theColor.getGreen(), theColor.getBlue(),

         (new float[3]));



      setLayout(new GridLayout(1,3,10,10);



      // Farbwechsel

      swatch = new Canvas();

      swatch.setBackground(theColor);



      // Control-Panel

      RGBcontrols = new ColorControls(this,

         "Red", "Green", "Blue",

         theColor.getRed(), theColor.getGreen(),

         theColor.getBlue());



      HSBcontrols = new ColorControls(this,

         "Hue", "Saturation", "Brightness",

         (int) (HSB[0] * 360), (int) (HSB[1] * 100),

         (int) (HSB[2] * 100));



      add(swatch);

      add(RGBcontrols);

      add(HSBcontrols);

      }

      public Insets insets() {

         return new Insets(10,10,10,10);

      }

      void update(ColorControls in) {

         Color c;

         String v1 = in.f1.getText();

         String v2 = in.f2.getText();

         String v3 = in.f3.getText();



         if (in == RGBcontrols) { // Änderung in RGB

            c = new Color(Integer.parseInt(v1),

               Integer.parseInt(v2),

               Integer.parseInt(v3);

            swatch.setBackground(c);

            float[] HSB = Color.RGBtoHSB(c.getRed(),c.getGreen(),

               c.getBlue(), (new float[3]));

            HSB[0] *= 360;

            HSB[1] *= 100;

            HSB[2] *= 100;

            HSBcontrols.f1.setText(String.valueOf(int)HSB[0]));

            HSBcontrols.f2.setText(String.valueOf(int)HSB[1]));

            HSBcontrols.f3.setText(String.valueOf(int)HSB[2]));

         }

         else { // Änderung in HSB

            int f1 = Integer.parseInt(v1);

            int f2 = Integer.parseInt(v2);

            int f3 = Integer.parseInt(v3);

            c = Color.getHSBColor((float)f1 / 360,

               (float)f2 / 100, (float)f3/100;

            swatch.setBackground(c);

            RGBcontrols.f1.setText(String.valueOf(c.getRed()));

            RGBcontrols.f2.setText(String.valueOf(c.getGreen()));

            RGBcontrols.f3.setText(String.valueOf(c.getBlue()));

         }

      }

   }

   class ColorControls extends Panel {

      TextField f1, f2, f3;

      ColorTest outerparent;



      ColorControls(ColorTest target,

         String l1, String l2, String l3,

         int v1, int v2, int v3) {

         this.outerparent = target;

         setLayout(new GridLayout(3,4,10,10));



      f1 = new TextField(String.valueOf(v1),10);

      f2 = new TextField(String.valueOf(v2),10);

      f3 = new TextField(String.valueOf(v3),10);



      add(new Label(l1, Label.RIGHT));

      add(f1);

      add(new Label(l2, Label.,RIGHT));

      add(f2);

      add(new Label(l3, Label.RIGHT));

      add(f3);

   }

   public Insets insets() {

      return new Insets(10,10,0,0);

   }

   public boolean action(Event evt, Object arg) {

      if (evt.target instanceof TextField) {

         this.outerparent.update(this);

         return true;

      }

      else return false;

   }

}

Zusammenfassung

Java-AWT (Abstract Windowing Toolkit) ist ein Paket mit Java-Klassen und Schnittstellen zur Entwicklung einer ausgereiften grafischen Benutzeroberfläche mit Mechanismen zur Anzeige von Text, Grafiken, Ereignissen, Komponenten der Benutzeroberfläche und plattformunabhängigen Layouts. Das AWT wird auch für die gesamte Funktionalität des HotJava-Browsers benutzt. Ferner sind Applets ebenfalls Bestandteil des AWT-Toolkits.

Heute war ein anstrengender Tag. Diese Lektion hat Sie ein großes Stück weitergebracht. Sie haben gelernt, wie Applets und Panels mit Aktionen versehen, wie Komponenten der Benutzeroberfläche erstellt und wie Interaktionen zwischen allen Elementen definiert werden. Mit dem heute gelernten Stoff und dem, was Sie morgen noch dazulernen, können Sie plattformunabhängige Java-Anwendungen entwickeln, die alles machen, was Sie sich vorstellen.


Fragen und Antworten

F: Sie haben viel über die Component- und Container-Klassen geschrieben, jedoch scheint es, daß Panels die einzigen Container-Objekte sind, die wir erstellen. Was bieten die Component- und Container-Klassen sonst noch?

A: Diese Klassen definieren Eigenschaften für Komponenten (allgemeine AWT-Komponenten) und Container (Komponenten, die andere Komponenten enthalten). Sie erzeugen zwar nicht unbedingt direkte Instanzen dieser Klassen, können aber Subklassen davon anlegen, wenn Sie zusätzliche Eigenschaften brauchen, die in der jeweiligen Standardklasse nicht enthalten ist. Wie bei den meisten Java-Klassen können Sie auch diese Klassen jederzeit um eigene Subklassen erweitern, wenn Sie das Verhalten dieser Superklassen verwenden möchten.

F: Kann ich eine Komponente der Benutzeroberfläche als spezifische x- und y-Position in den Bildschirm stellen?

A: Mit den im AWT-Toolkit vorhandenen Layout-Managern geht das nicht. Das ist eigentlich auch gut so, weil Sie nicht wissen, in welcher Anzeigeumgebung Ihr Applet ausgeführt wird, welche Fonts installiert sind usw. Durch Verwendung der im AWT enthaltenen Layout-Manager stellen Sie sicher, daß jeder Teil Ihres Fensters auf allen Plattformen angezeigt, gelesen und benutzt werden kann. Bei hartcodierten Layouts ist das nicht sicher.

F: Ich habe mir das AWT-Toolkit angesehen und ein Paket namens peer entdeckt. Außerdem wird an vielen Stellen in der API-Dokumentation auf die peer-Klassen verwiesen. Was bewirken diese Klassen?

A: peer-Klassen sind für die plattformspezifischen Teile des AWT zuständig. Wenn Sie beispielsweise ein AWT-Fenster erstellen, haben Sie eine Instanz der Window-Klasse, die allgemeine Fenstereigenschaften bereitstellt. Daneben gibt es eine Instanz von WindowPeer, die ein spezifisches Motiv-Fenster unter X-Windows, ein Macintosh-Fenster für den Macintosh oder ein Fenster für Windows 95 erstellt. Die peer-Klassen handhaben auch die Kommunikation zwischen dem Fenstersystem der Plattform und dem Java-Fenster. Durch Trennen der allgemeinen Komponenteneigenschaften (der AWT-Klassen) von der eigentlichen Systemimplementierung und vom Aussehen (der peer-Klassen) können Sie sich auf das Verhalten Ihrer Java-Anwendung konzentrieren und die plattformspezifischen Einzelheiten der Java-Implementierung überlassen.

F: Das AWT-Toolkit enthält, wie ich sehe, noch einige Funktionalitäten, die Sie nicht behandelt haben. Warum?

A: Da die Einführung und das Erlernen der Java-Grundlagen viel Zeit in Anspruch nimmt, ist für die AWT-Zusätze in diesem Buch kein Platz mehr. Fenster, Menüs und Dialogfelder werden morgen behandelt. Was die übrigen Merkmale von AWT betrifft, verweise ich auf die API-Dokumentation. Beginnen Sie mit der Applet-Klasse und sehen Sie sich die aufrufbaren Methoden an. Sehen Sie sich Panel an, von der Applet erbt, dann haben Sie auch die Funktionalität dieser Klasse schon abgedeckt. Die Superklasse von Panel ist Container, die ebenfalls interessante Details enthält. Schließlich wäre da noch Component. Was Sie damit alles machen können, wird in der API-Dokumentation beschrieben. Einiges davon ist sicherlich für Sie interessant. Wie gesagt, ist das Thema dieses Buches auf das Erlernen der Java-Grundlagen beschränkt.


Copyright ©1996 Markt&Technik
Buch- und Software- Verlag GmbH
Alle Rechte vorbehalten. All rights reserved.

Schreiben Sie uns!

Previous Page TOC Index Next Page See Page