Kurzeinführung in Java - BFH-TI Staff

Werbung
Berner Fachhochschule
Hochschule für Technik und Informatik, HTI
Fachbereich Elektro- und Kommunikationstechnik
Labor für Technische Informatik
Kurzeinführung
in Java
GUI-Programmierung & Event-Handling
Applets
Threads
Ausnahmen
Ein- und Ausgabe
© 2008, HTI Biel
E. FIROUZI
Dateiname: Skript_Einf_Java_Teil_2
Erstellt am: 10. September 2009
Autor: E FIROUZI
Version: 3.0
Inhaltsverzeichnis
Inhaltsverzeichnis
4 GUI-Programmierung & Event-Handling
4.1 Struktur von GUI-Anwendungen
4.1.1 Hierarchie der Fenster: Fenster im Fenster
4.1.2 Klassenhierarchie von GUI-Bausteinen
4.1.3 Elementare Controls und ihre Einbindung
4.2.1 Anordnung der Komponenten
4.2 Layoutmanager
4.2.1 Anordnung der Komponenten
4.2.2 BorderLayout
4.2.3 FlowLayout
4.2.4 GridLayout
4.2.5 GridBagLayout
4.2.6 CardLayout
4.2.7 Schachtelung der Layouts
4.3 Ereignissteuerung
4.3.2 Typen von Ereignissen
4.3.3 Quellen von Ereignissen
4.3.4 Beobachter von Ereignisse
4.3.5 Adapter
4.4 Elementare Controls in Benutzeroberfläche
4.4.1 Zeichenflächen: Canvas
4.4.2 Schalter: Button
4.4.3 Auswahl
4.4.4 Checkbox und Radiobutton
4.4.5 Statischer Text
4.4.6 Textfelder
4.4.7 Rollbalken
4.4.8 Menüs in Java
5 Applets
5.1 Einführung
5.1.1 Die HTML-Seiten
5.1.2 Appletbeispiel
5.2 Funktionsweise von Applets
5.2.1 Speicherung von Applets
5.2.2 Sicherheit von Applets
5.3.1 Die PARAM- Funktion
5.3.1 Appletbeispiel für
5.4 Klänge und Bilder
5.4.1 Klänge
5.4.2 Bilder
6 Threads
0 Ausnahmen
7.1 Einführung
7.1.1 Programmbeispiel
7.2 Funktionsprinzip
7.2.1 Eine mögliche Implementierung der Ausnahmenbehandlung
Seite 2
4
4
4
5
6
7
7
7
7
9
10
11
13
14
15
18
19
19
20
21
21
24
26
27
29
29
29
33
36
36
36
36
38
40
40
41
41
44
44
45
48
51
51
51
52
52
Inhaltsverzeichnis
7.3 Vorteile der Ausnahmebehandlung in Java
7.4 Klassen und Ausnahmen
7.4.1 Programmbeispiel
8 Ein- und Ausgabe
8.1 Eingabe in Java
8.1.1 Eingabe mit der byteorientierten Stream-Klassen
8.1.2 Eingabe mit der zeichenorientierten Reader-Klassen
8.1.3 Die Standard Eingabe
8.2 Ausgabe in Java
8.2.1 Ausgabe mit der byteorientierten Stream-Klassen
8.2.2 Ausgabe mit der zeichenorientierten Writer-Klassen
8.2.3 Die Standard-Ausgabe
8.3 Anwendungs-Beispiele
8.3.1 Byteweise Verarbeitung von Dateien
8.3.2 Blockweise Verarbeitung von Daten
8.3.3 Daten im Format für das Internet verarbeiten
Seite 3
52
52
53
55
55
55
56
58
59
59
60
60
60
61
62
63
4 GUI-Programmierung & Event-Handling
4 GUI-Programmierung & Event-Handling
Das JDK enthält seit der Version 1.0 als „Abstract Windows Toolkit“ in dem Package java.awt eine
umfangreiche Sammlung von Klassen zur Programmierung von grafischen Anwendungen und
Benutzeroberflächen (GUI = Graphical User Interface). Damit können sowohl für Applets in HTML-Seiten als
auch für Anwendungen, die unter den jeweiligen Betriebssystemen laufen, Vektorgrafiken und die Interaktion
von Anwendungen mit der GUI programmiert werden.
Für grafische Benutzeroberflächen gibt es im JDK die üblichen Möglichkeiten: Menus, Maus, Steuerelemente
und Dialoge. Bei Applets gibt es Einschränkungen, denn aus Sicherheitsgründen dürfen die in Web-Seiten
eingebetteten Applikationen nicht auf lokale Daten zugreifen. Damit entfallen für Applets die Dialoge zum
Anzeigen von Inhaltsverzeichnissen und zum Auswählen von Dateien.
rIm Hinblick auf portable Anwendungen und die verschiedenen Grössen von Bildschirmen im Internet, wurden
in Java mit den sog. Layout-Managern flexible Methoden zur variablen Gestaltung von Benutzeroberflächen
bereitgestellt.
4.1 Struktur von GUI-Anwendungen
Mit Java 2 kann man GUI-Anwendungen nicht nur auf das AWT aufsetzen, sondern auch das „SwingKlassensystem“ als Basis für Anwendungen benutzen. Beim Design von Swing wurde bei den elementaren
Möglichkeiten auf weitgehende Kompatibilität zu Ideen und Struktur des AWT geachtet. In den folgenden
Kapiteln werden nur Beispiele mit dem AWT-Klassensystem als Basis dargestellt. Die entsprechenden Swing
Darstellungen befinden sich im Jobst-Buch.
4.1.1 Hierarchie der Fenster: Fenster im Fenster
Die grafische Anwendung besteht aus einem Hauptfenster. Dies ist im Sinne von Java ein „Container“, der
untergeordnete Fenster enthalten kann. Jeder dieser Container kann seinerseits wieder Container als
Komponenten enthalten.
Der einfachste Container in AWT ist ein „Panel“, der auch die Basis für „Applet“ bildet. Aber Panel
können auch zur Montage von Controls oder anderer Komponenten in anderen Fenster als Komponenten
eingetragen werden.
Die Klasse „Window“ steht für selbstständige Fenster. Ein Window ist ein rechteckiges Stück auf dem
Bildschirm ohne Rahmen und Titelzeile. Ein „Frame“ ist ein Window mit Rahmen und Titelzeile. Ein Frame
kann eine Menüleiste enthalten und steht als Prototyp für GUI-Anwendungen zur Verfügung.
Programmbeispiel
import java.awt.*;
public class MyFrame extends Frame {
MyFrame (String Title) {
super(Title);
add(new Button("AWT Button"));
setSize(300, 100);
setVisible(true);
}
public static void main(String[] args){
new MyFrame("Java application with AWT");
}
}
Seite 4
4 GUI-Programmierung & Event-Handling
Hinweis
Im obigen Beispiel ist „MyFrame“ eine abgeleitete Klasse von Frame. Dies wird durch
public class MyFrame extends Frame
zum Ausdruck gemacht.
Die Eigenschaften des Fensters werden im Konstruktor von MyFrame festgelegt. Das Fenster erhält durch den
Aufruf vom Konstruktor der Mutterklasse Frame mit einem String einen Namen, welcher in seiner obersten
Leiste erscheint. Die verschiedenen Komponenten der grafischen Benutzeroberflächen müssen systematisch
erzeugt und mit der Methode
public void add(Component oneComponent)
zum Container hinzugefügt werden. Hierdurch wurde in diesem Beispiel der Schalter „AWT Button“ dem
Hauptfenster zugeordnet. Die Grösse in Pixel und die Sichtbarkeit des Fensters können beziehungsweise mit den
Methoden „setSize()“ und „setVisible()“ festgelegt werden.
In der Methode „main()“ wird ein Objekt der Klasse „MyFrame“ erzeugt. Damit wird das Fenster auf dem
Bildschirm sichtbar.
Ausgabenmöglichkeit
4.1.2 Klassenhierarchie von GUI-Bausteinen
Die verschiedenen Komponenten der grafischen Benutzeroberflächen werden durch eine Klassenhierarchie
abgebildet, die ihre Wurzel in der abstrakten Klasse „java.awt.Component“ hat. Sie verfügen damit über
alle Attribute und Methoden von „Component“, welche zur Beeinflussung der Darstellungsweise und zum
Umgang mit Ereignissen zur Verfügung stehen:
•
Festlegung und Ermitteln von Position und Grösse: getSize, getX, getY, setSize,
setLocation usw.
•
Festlegung und Ermitteln von grafischen Eigenschaften: getForeground, setBackground,
setFont, getCursor usw.
•
Anzeigen und Neuzeichnen von Komponenten: setVisible, paint, rePaint usw.
•
Ereignisverarbeitung.
Die abstrakte Klasse „Container“ ist die wichtigste Klasse von Component. Sie dient hauptsächlich zur
Zusammenfügung der Steuerelemente in den Fenstern oder Dialogen, und stellt die folgenden Methoden zur
Verfügung:
•
Hinzufügen einer Komponente zu einem Container: add()
•
Entfernen von Komponenten aus einem Container: remove, removeAll usw.
•
Festlegen und Ermitteln des aktuellen Layouts: setLayout, getLayout, doLayout usw.
Die Klassenhierarchie der AWT-Controls ist in der nachfolgenden Abbildung dargestellt.
Seite 5
4 GUI-Programmierung & Event-Handling
java.awt.Component
java.awt.Button
java.awt.Canvas
java.awt.Checkbox
java.awt.Choice
java.awt.Label
java.awt.List
java.awt.Scrollbar
java.awt.TextComponent
java.awt.TextArea
java.awt.TextField
jawa.awt.Container
java.awt.ScrollPane
java.awt.Panel
java.awt.Applet
java.awt.Window
jawa.awt.Frame
jawa.awt.Dialog
jawa.awt.FileDialog
4.1.3 Elementare Controls und ihre Einbindung
In Java haben sich bei Anwendungen für grafische Benutzeroberflächen eine Reihe von festen Steuerelementen
durchgesetzt: Schalter, Rollbalken usw. Die folgende Tabelle enthält diese sog. Controls aus dem Package
jawa.awt. Eine vollständige Beschreibung von diesen Controls befindet sich im Kapitel 4.4 Elementare
Controls in Benutzeroberfläche.
AWT Klassen
Canvas
Component
Panel
Choice
Scrollbar
Checkbox
Button
Label
List
TextComponent
TextArea
TextField
Beschreibung
Zeichenfläche für Programme
Basis für Komponenten
„Pinnwand“ als Container für Controls
Auswahl aus einem Pop-Up- Fenster
Rollbalken
Checkbox und Radiobuttons
Schalter
Statischer Text
Auswahl aus einer Liste von Möglichkeiten
Oberbegriffe für Textfelder
Textfeld mit mehreren Zeilen
Textfeld mit einer Zeile
Canvas ist eine Zeichenfläche, auf welcher Grafikausgaben mit den Elementen der Grafik-Programmierung
java.awt.Graphics möglich sind. Damit kann entweder Text ausgeben, oder Linien und Figuren
gezeichnet werden.
Choice implementiert eine Pop-Up- Menü mit einer Liste von Strings, aus denen nur einer gleichzeitig
ausgewählt werden kann.
Mit der Klasse Scrollbar kann ein Rollbalken dargestellt werden, in welchem die Position des Schiebereglers
einem int- Wert entspricht. Dieser Wert kann genauso eingestellt werden, wie die Abstufung der Bewegung des
Schiebereglers.
Seite 6
4 GUI-Programmierung & Event-Handling
Die Klasse „Checkbox“ implementiert Checkboxen, welche aus einem Markierungsfeld, das selektiert oder
nicht selektiert werden kann, und einem daneben angeordneten Text bestehen.
Die Klasse „TextComponent“ ist die Basis für die Klassen „TextArea“ und „TextField“. Sie definiert
die grundlegenden Methoden zum Umgang mit Textfeldern. Die Klasse „TextArea“ stellt ein
Texteingabefenster bereit, das sich auch über mehrere Zeilen erstrecken kann. Es ist möglich, Textzeilen zu
markieren oder zu löschen sowie einen neuen Text einzufügen. Die Klasse „TextField“ stellt ein einzeiliges
Texteingabefeld zur Verfügung.
AWT-Controls in einem Rahmen
Choice
Button
CheckBox
TextField
CheckBox
as radio
buttons
List
ScrollBar
4.2 Layoutmanager
GUI-Systeme mit starren Anordnungen ihrer Komponenten sind für Anwendungen im Internet nicht ausreichend:
Es gibt verschiedene Betriebssysteme wie Macintosh, Microsoft-Windows oder X-Windows und alle
Bildschirmgrössen sind denkbar.
Java erlaubt einerseits feste Anordnungen von Komponenten, aber auch anderseits die Platzierung der
Komponenten nach diversen Strategien.
4.2.1 Anordnung der Komponenten
Fenster können vom Anwender verkleinert und vergrössert werden. Dies betrifft insbesondere auch alle
Komponenten in den Fenstern. In Java wird durch die sog. Layout Manager Abhilfe geschafft. Jeder
Container hat seinen eigenen Layoutmanager, welcher für die Anordnung der Komponenten zuständig ist.
Layoutmanager können unterschiedliche Strategien hinsichtlich der Platzierung der Komponenten eines
Containers verfolgen. Java bietet seit JDK 1.0 fünf verschiedene Möglichkeiten. Die folgende Tabelle enthält
die Layoutmanager aus dem Package jawa.awt, welche für jeden Container frei zuordenbar sind.
Layoutmanager
BorderLayout
CardLayout
FlowLayout
GridLayout
GridBagLayout
Strategie der Anordnung
Anordnung der Komponenten: links, rechts, oben, Mitte und unten
Überlagerung der Komponenten
Komponenten nach Reihe anordnen
Komponenten in Matrix-Raster anordnen
Komponenten in einem flexiblen Matrix-Raster anordnen: Zellen in Abhängigkeit
von anderen Zellen positionieren
4.2.2 BorderLayout
Im JDK wird bei Frame, Applet und Dialog standardmässig ein sog. BorderLayout angenommen.
Dieses Layout kennt für seine vier Ränder und die Mitte die Bezeichnungen, welche der Windrose entsprechen:
Seite 7
4 GUI-Programmierung & Event-Handling
North
West
Center
East
South
Anwendung
BorderLayout löst übliche Anordnungsprobleme für Zeichenfläche und Controls. Controls können am Rand
in Form sog. Toolbars einmontiert werden. Eine Toolbar wird dann seinerseits ein Panel sein, auf dem Schalter
oder Knöpfe erscheinen.
Programmbeispiel
import java.awt.*;
class BorderDemo extends Frame {
public BorderDemo (String Title) {
super (Title);
setSize (300, 150);
add (new Button ("North"), BorderLayout.NORTH);
add (new Button ("South"), BorderLayout.SOUTH);
add (new Button ("West"),
BorderLayout.WEST);
add (new Button ("East"),
BorderLayout.EAST);
add (new Button ("Center"), BorderLayout.CENTER);
setVisible(true);
}
public static void main (String[] args) {
new BorderDemo("BorderLayout");
}
}
Hinweis
Im Konstruktor werden die erstellten Schalter mit der Methode
public void add(Component oneComponent, Object constraints)
zu dem Fenster hinzugefügt. Hierbei werden sie beim Layoutmanager mit dem Objekt constraints registriert.
BorderLayout nützt diese Parameter, um die Komponente einer bestimmten Stelle zuzuordnen. Die folgende
Tabelle enthält die Attribute für die verschiedenen Ausrichtungen:
Ausrichtungs-Parameter
BorderLayout.NORTH
BorderLayout.SOUTH
BorderLayout.WEST
BorderLayout.EAST
BorderLayout.CENTER
Beschreibung
Anordnung der Komponente oben im Fenster
Anordnung der Komponente unten im Fenster
Anordnung der Komponente in der rechten Seite des Fensters
Anordnung der Komponente in der linken Seite des Fensters
Anordnung der Komponente in der Mitte des Fensters
Seite 8
4 GUI-Programmierung & Event-Handling
Ausgabenmöglichkeit
4.2.3 FlowLayout
Im JDK wird bei Panel standardmässig ein sog. FlowLayout angenommen. Bei diesem Layout werden die
Komponenten der Reihe nach von links nach rechts in der Folge ihres Eintrags in einem Container angeordnet.
Wenn eine „Zeile“ voll ist, wird die nächste Komponente in die nächste Zeile platziert. Die folgende Tabelle
enthält die Attribute für die verschiedenen Ausrichtungen:
Ausrichtungs-Parameter
FlowLayout.LEFT
FlowLayout.CENTER
FlowLayout.RIGHT
FlowLayout.LEADING
FlowLayout.TRAILING
Beschreibung
Linksbündige Anordnung jeder Zeile
Zentrierte Anordnung jeder Zeile (Default)
Rechtsbündige Anordnung jeder Zeile
Für sprachabhängige Ausrichtung. Bei Links-Rechts Ausrichtung wie LEFT.
Für sprachabhängige Ausrichtung. Bei Links-Rechts Ausrichtung wie RIGHT.
Programmbeispiel
import java.awt.*;
public class FlowDemo extends Frame {
FlowDemo (String Title) {
super (Title);
setLayout (new FlowLayout (FlowLayout.LEFT));
setSize(200, 130);
for (int i = 1; i <= 7; i++) {
String s = "";
for (int j = 0; j < i; j++) {
s += "S";
}
add(new Button (s));
}
setVisible(true);
}
public static void main (String[] args) {
new FlowDemo("FlowLayout");
}
}
Hinweis
Da bei Frame standardmässig ein BorderLayout angenommen wird, muss zuerst der Layoutmanager des
Containers auf BorderLayout gesetzt werden. Deshalb wird hier ein Objekt der Klasse FlowLayout mit der
linksbündigen Ausrichtung erzeugt und mit der Methode
public void setLayout(LayoutManager mgr)
Seite 9
4 GUI-Programmierung & Event-Handling
dem Container zugeordnet. Anschliessend werden die erstellten Schalter mit der add- Methode zu dem Fenster
hinzugefügt.
Ausgabenmöglichkeiten
FlowLayout.LEFT
FlowLayout.CENTER
FlowLayout.RIGHT
4.2.4 GridLayout
Mit GridLayout kann man Komponenten matrixartig in einem n x m- Raster aus n Zeilen und m Spalten
anordnen.
Programmbeispiel
import java.awt.*;
public class GridDemo extends Frame {
GridDemo (String Title) {
super (Title);
setLayout (new GridLayout (2, 4));
setSize(300, 200);
for (int i = 0; i <= 7; i++) {
add (new Button ("Button " + i));
}
setVisible (true);
}
public static void main (String[] args) {
new GridDemo ("GridLayout");
}
}
Hinweis
Da bei Frame standardmässig ein BorderLayout angenommen wird, muss hier ebenfalls die Methode
setLayout den neuen Layoutmanager festlegen. Deshalb wird hier ein Objekt der Klasse GridLayout
erzeugt und dem Container zugeordnet.
Beim Erzeugen des GridLayout kann die Zeilenzahl (zuerst) und die Spaltenzahl angegeben werden. Mit zwei
weiteren int- Werten können zusätzlich horizontale und vertikale Abstände in Pixel zwischen den „Feldern“ der
„Tabelle“ festgelegt werden.
Seite 10
4 GUI-Programmierung & Event-Handling
Ausgabenmöglichkeit
4.2.5 GridBagLayout
GridBagLayout erlaubt eine rasterartige Anordnung von Komponenten. Im Gegensatz zu GridLayout lässt
sich die Anordnung der Komponenten noch beeinflussen. Diese Steuerung erfolgt mit diversen Attributen der
Klasse GridBagConstraints.
Steuerungs-Attributen
gridx, gridy
gridwidth, gridheight
fill
weightx, weighty
Beschreibung
Mit diesen Parametern gibt man die linke, obere Ecke der Komponente an. Die
am weitesten links oben stehende Komponente hat die Adresse gridx = 0 und
gridy = 0.
Mit dem Default-Wert GridBagConstraints.RELATIVE für gridx
(bzw. gridy) bestimmt man, dass die Komponente rechts (bzw. unter) der
zuletzt zu dem Container hinzu gefügten Komponente angeordnet wird.
Mit diesen Parametern mit den Default-Werten 1 legt man die Anzahl der
Zeilen (gridwidth) bzw. die Anzahl der Spalten (gridheight) fest.
Der Wert GridBagConstraints.REMAINDER bestimmt, dass die
Komponente die Letzte in der Zeile (gridwidth) bzw. in der Spalte
(gridheight) ist.
GridBagConstraints.RELATIVE bewirkt, dass die Komponente die
Vorletzte in der Zeile (gridwidth) bzw. der Spalte (gridheight) ist.
Wenn eine Komponente kleiner als der ihr zur Verfügung stehende Bereich ist,
wird sie gemäss diesem Parameter an die Grösse angepasst.
GridBagConstraints.NONE
Keine Anpassung (Default Wert)
GridBagConstraints.HORIZONTAL Nur horizontale Anpassung
GridBagConstraints.VERTICAL
Nur vertikale Anpassung
GridBagConstraints.BOTH
Horizontale und vertikale
Anpassung
Dieser Parameter legt die Verteilung einer Komponente in x- und y-Richtung
fest.
Programmbeispiel
import java.awt.*;
public class GridBagDemo extends Frame {
Button b[] = new Button[6];
GridBagDemo (String Title) {
super(Title);
GridBagLayout l = new GridBagLayout();
setLayout(l);
setSize(300,200);
Seite 11
4 GUI-Programmierung & Event-Handling
for(int i = 0; i < b.length; i++){
b[i] = new Button("Button " + i);
}
GridBagConstraints c = new GridBagConstraints ();
c.fill = GridBagConstraints.BOTH;
/* Button 0 */
c.weightx = 1;
c.weighty = 1;
c.gridheight = 2;
l.setConstraints(b[0], c);
add(b[0]);
/* Button 1 */
c.gridheight = 1;
l.setConstraints(b[1], c);
add(b[1]);
/* Button 2 */
l.setConstraints(b[2], c);
add(b[2]);
/* Button 3 */
c.gridwidth = GridBagConstraints.REMAINDER;
l.setConstraints(b[3], c);
add(b[3]);
/* Button 4 */
c.gridwidth = GridBagConstraints.RELATIVE;
l.setConstraints(b[4], c);
add(b[4]);
/* Button 5 */
c.gridwidth = GridBagConstraints.REMAINDER;
l.setConstraints(b[5], c);
add(b[5]);
setVisible(true);
}
public static void main (String[] args) {
new GridBagDemo ("GridBagLayout");
}
}
Hinweis
Da bei Frame standardmässig ein BorderLayout angenommen wird, muss wieder die Methode
„setLayout()“ den neuen Layoutmanager festlegen. Deshalb wird hier ein Objekt der Klasse
GridBagLayout erzeugt und dem Container zugeordnet. Zusätzlich wird ein Spezifikationsobjekt der Klasse
GridBagConstraints erstellt, damit die Anordnung der Komponenten beeinflusst werden kann.
Die Methode
public void setConstraints (Component oneComponent, GridBagConstraints
constraints)
verknüpft systematisch die Komponenten mit den Spezifikationsobjekten. In obigem Beispiel wird immer mit
demselben Spezifikationsobjekt c gearbeitet, denn setConstraints benutzt jeweils nur eine Kopie von
diesem Objekt.
Seite 12
4 GUI-Programmierung & Event-Handling
Beim ersten Schalter (mit der Aufschrift „Schalter0“) wird beim Spezifikationsobjekt das Attribut
gridheight auf 2 gesetzt. Damit umspannt diese Komponente zwei Zeilen. Danach wird dieses Attribut auf 1
zurückgesetzt. Die Steuerung der Zeilen übernimmt das Attribut gridwidth. Wenn dieses auf
GridBagConstraints.REMAINDER gesetzt wird, füllt die Komponente den Rest der Zeile aus.
Ausgabenmöglichkeit
4.2.6 CardLayout
CardLayout sorgt dafür, dass nur jeweils eine der Komponenten eines Containers sichtbar ist (wie in einem
Kartenstapel). Mit Anrufen wie first(Container), last(Container), next(Container) kann
zwischen Karten hin- und hergeschaltet werden.
Anwendung
Mit CardLayout kann man zwischen verschiedenen Sätzen von Steuerelementen schalten. Damit kann man
eine komplizierte Auswahl von den Parametern realisieren, wie man sie etwa mit tabulatorartigen
Steuerelementen in modernen Betriebssystemen findet. Es muss ein Steuerelement zur Steuerung der Anzeige
sichtbar bleiben.
Programmbeispiel
import java.awt.*;
public class CardDemo extends Frame {
CardDemo (String Title) {
super (Title);
setLayout (new CardLayout());
setSize(300,150);
for(int i = 0; i <=7; i++) {
add("Button " + i, new Button("Button " + i));
}
setVisible(true);
}
public static void main (String[] args) {
CardDemo cardDemo = new CardDemo ("CardLayout");
/* Definition of a reference for CardLayout,
which is initialized with the layout manager of CardDemo */
CardLayout cl = (CardLayout) cardDemo.getLayout ();
Seite 13
4 GUI-Programmierung & Event-Handling
/* Show the first card */
cl.first (cardDemo);
for(int i = 0; i < 5; i++) {
/* The component of the container can be shown step by step,
with the help of break points */
cl.next (cardDemo);
}
/* Show the last card */
cl.last (cardDemo);
}
}
Hinweis
Da bei Frame standardmässig ein BorderLayout angenommen wird, muss wieder die Methode
„setLayout()“ den neuen Layoutmanager festlegen. Deshalb wird hier ein Objekt der Klasse CardLayout
erzeugt und dem Container zugeordnet. Die Methode
public void add (String Name, Component oneComponent)
fügt dem Container die erzeugte Komponente unter der Bezeichnung Name hinzu.
In der Hauptmethode werden ein Objekt der Klasse „CardDemo“ und eine Referenz „cl“ der Klasse
CardLayout erzeugt. Die Referenz cl wird mit der Hilfe der Methode
public LayoutManager getLayout()
initialisiert, damit sie auf den Layout Manager des Containers zeigt. Hierdurch kann cl für das Schalten
zwischen den verschiedenen Sätzen von Steuerelemente benutzt werden. Am Ende der Hauptmethode wird mit
den Methoden
public void first(Container parent)
public void next(Container parent)
public void last(Container parent)
der Klasse CardLayout jeweils nur eine der Komponenten des Containers sichtbar gemacht.
Ausgabenmöglichkeit
.....
4.2.7 Schachtelung der Layouts
Jeder Container kann andere Container enthalten. Da jedem Container ein Layout-Manager zugeordnet ist, kann
man innerhalb eines Layouts vollständig Layouts verschachteln. Damit lassen sich komplexe Anordnungen der
Steuerelemente aufbauen. Das folgende Beispiel zeigt, wie in ein BorderLayout fünf Container integriert
werden. Dabei hat jeder dieser Container ein anderes Objekt der Klasse GridLayout als Manager.
Programmbeispiel
import java.awt.*;
Seite 14
4 GUI-Programmierung & Event-Handling
class MyPanel extends Panel {
public MyPanel (String Text, int Line, int Column){
setLayout(new GridLayout(Line, Column));
for(int i = 0; i < Line * Column; i++){
add(new Button(Text + " - " + (i+1)));
}
}
}
public class NestedDemo extends Frame {
NestedDemo (String Title){
super(Title);
setSize(500, 300);
add(BorderLayout.NORTH, new MyPanel("N",
add(BorderLayout.SOUTH, new MyPanel("S",
add(BorderLayout.WEST,
new MyPanel("W",
add(BorderLayout.EAST,
new MyPanel("E",
add(BorderLayout.CENTER, new MyPanel("C",
setVisible(true);
}
1,
1,
5,
7,
4,
4));
8));
1));
1));
3));
public static void main (String[] args) {
new NestedDemo ("Nested Layouts");
}
}
Hinweis
Die Klasse „MyPanel“ wurde hier für die Schachtelung der Layouts definiert. MyPanel ist eine Tochterklasse
von Panel, und enthält ein Objekt der Klasse „GridLayout“ als Layoutmanager. In Java sind Panels sog.
Pinnwände, welche als Container für Controls verwendet werden können. Die Parameterliste des Konstruktors
„MyPanel“ enthält den auszugebenden Text sowie die Anzahl Zeilen und Spalten für den Layoutmanager.
Im Konstruktor von „NestedDemo“ werden Objekte der Klasse „MyPanel“ erzeugt und mit der addMethode ins Hauptfenster nach dem Windrosenmuster platziert.
Ausgabenmöglichkeit
4.3 Ereignissteuerung
Bei Anwendungen für grafische Benutzeroberflächen haben sich eine Reihe von festen Steuerelementen
durchgesetzt: Schalter, Rollbalken usw. Diese sog. „Controls“ werden auch von Java unterstützt. Darüber hinaus
gibt es bei grafischen Benutzeroberflächen eine komplexe Wechselwirkung zwischen dem Anwender und dem
Seite 15
4 GUI-Programmierung & Event-Handling
Programm.
Zur Implementierung von ereignisgesteuerten Programmen gibt es die folgenden Strategien:
a)
Definition von Einsprungspunkten für diverse Aktionen: Mausbewegung, Tastatur, Ziehen von Rollbalken,
Drücken von Schalter usw.
b) Definition eines Einsprungpunktes und Verzweigen zur Behandlung auf Grund des Typs des speziellen
Ereignisses.
c)
Konzept der Ereignisse mit Quellen von Ereignissen, sowie Beobachtern.
Mausbewegung
Maustaste gedruckt
Taste gedrückt
Programm
Rollbalken betätigt
Schalter gedruckt
Textenigabe abgeschlossen
Neuer Bidschirmaufbau erfordelich
Die Strategien a) und b) haben als Nachteil eine implizite Verbindung der Ereignisse mit dem Programm zur
Folge. Die resultierenden Ergebnisse sind die Laufzeit und die komplexen Konstruktionen bei der Anmeldung
einzelner Programme zur Bearbeitung von Ereignissen. Deshalb wurde ab dem JDK 1.1 die Strategie c)
eingeführt. In diesem Fall werden Ereignisse explizit zu Beobachtern zugeordnet. Jede Klasse kann
Beobachterschnittstellen für bestimmte Ereignisse bzw. Gruppen von Ereignissen implementieren. Die
Anmeldung von Beobachtern zur Benachrichtigung vom Eintreten bestimmter Ereignisse muss jedoch immer
explizit erfolgen.
4.3.1 Das „Delegation Event Model“ in Java AWT 1.1
Im JDK 1.1 wurde die Bearbeitung von Ereignissen auf das sog. „Delegation Event Model“ nach dem
Beobachter-Entwurfmuster umgestellt. In diesem Model kennt die Ereignissteuerung für jedes Ereignis eine
Quelle „Source“ sowie die Beobachter „Listener“. Die Zuordnung der Quelle zum Bearbeiter ist frei
programmierbar und muss explizit durchgeführt werden.
Ereignis
Quelle
Beobachter
Bei der Verbreitung von Ereignissen ist zwischen „single-cast“ und „multi-cast“ zu unterscheiden. Für singlecast- Ereignisse wird der Beobachter mit „setxxListerner“ festgelegt. Für multi-cast- Ereignisse wird der
Beobachter mit „addxxListerner“ hinzugefügt.
Die Bearbeiter müssen spezifisch die „xxListerner“- Schnittstellen implementieren. Die Ereignissteuerung
ruft eine Methode dieser Schnittstelle auf. Als Parameter wird eine Unterklasse von EventObject mit der
Beschreibung des Ereignisses übergeben.
Die Quelle ist ein Objekt, die Ereignisse neu anlegt. Die Quelle definiert den Typ des Ereignisses, indem sie
Methoden zur Registrierung der Beobachter anbietet. Die Quelle kann z.B. eine GUI-Komponente sein. Der
Bearbeiter ist ein sog. „Adapter“, der eine oder mehrere xxListener- Schnittstellen implementiert.
Seite 16
4 GUI-Programmierung & Event-Handling
Hierarchie der Ereignisse
Die verschiedenen Typen von Ereignissen werden durch eine Klassenhierarchie abgebildet, die ihre Wurzel in
der Klasse java.util.EventObjekt hat. In dieser Klassenhierarchie werden die diversen Ereignisse durch
eine Klasse modelliert.
java.util.EventObject
java.awt.AWTEvent
java.awt.event.ActionEvent
java.awt.event.AdjustmentEvent
java.awt.event.HierarchyEvent
java.awt.event.InputMethodEvent
java.awt.event.InvocationEvent
java.awt.event.ItemEvent
java.awt.event.TextEvent
java.awt.event.ComponentEvent
java.awt.event.ContainerEvent
java.awt.event.FocusEvent
java.awt.event.PaintEvent
java.awt.event.WindowEvent
java.awt.event.InputEvent
jawa.awt.event.KeyEvent
jawa.awt.event.MouseEvent
Programmbeispiel
Ein Programm, das in einem Fenster abläuft, muss sich auf irgendeine Weise anhalten lassen. Eine weithin
akzeptierte Möglichkeit besteht darin, dass der Anwender in einer oberen Ecke des Fensters auf einen Knopf zum
Schliessen drückt. Das Drücken ist ein Ereignis und kann von einem der Listener im AWT-Paket Event
entdeckt werden.
Das folgende Beispiel erzeugt ein Fenster, welches mit einem Knopfdruck in der oberen Ecke geschlossen
werden kann.
import java.awt.*;
import java.awt.event.*;
class Frame1 extends Frame implements WindowListener {
public Frame1(String Title){
super(Title);
setSize(300, 100);
setVisible(true);
// Affectation of the (window) events to the listener
addWindowListener(this);
}
Seite 17
4 GUI-Programmierung & Event-Handling
// Tasks of the window listener !
public void windowClosed
(WindowEvent
public void windowDeiconified(WindowEvent
public void windowIconified (WindowEvent
public void windowActivated (WindowEvent
public void windowDeactivated(WindowEvent
public void windowOpened
(WindowEvent
public void windowClosing
(WindowEvent
System.exit(0);
}
event){}
event){}
event){}
event){}
event){}
event){}
event){
public static void main(String[] args){
new Frame1("1. Frame");
}
}
Hinweis
In diesem Beispiel wurde Frame1 explizit als Quelle und Beobachter von Fensterereignissen (WindowEvent)
definiert. Dies wird durch
addWindowListener(this);
zum Ausdruck gemacht.
Frame1 muss als Beobachter alle Methoden der Schnittstelle „WindowListener“ implementieren, auch
wenn diese, wie im obigen Beispiel, nicht benutzt werden. Die Methode „windowClosing“ von dieser
Schnittstelle wird nach dem Drucken des Knopfes in der oberen Ecke des Fensters von der Ereignissteuerung
aufgerufen. Deshalb enthält sie die Anweisung „System.exit(0)“, welche das Programm wie gewünscht
beendet.
Ausgabenmöglichkeit
close
4.3.2 Typen von Ereignissen
Das AWT 1.1 unterscheidet bei Ereignissen zwischen „Low-Level“ und „Semantic-Level“. Low-LevelEreignisse modellieren einfache Eingaben (Tasten, Maus) oder Fensterereignisse, welche in der folgenden
Tabelle aufgelistet worden sind:
Low-Level- Ereignisse
ComponentEvent
FocusEvent
KeyEvent
MouseEvent
ContainerEvent
WindowEvent
Beschreibung
Die Komponente wurde vergrössert, verkleinert, verschoben.
Die Komponente hat den Fokus erhalten, verloren.
Eine Taste wurde gedrückt, losgelassen ...
Maustaste gedrückt, losgelassen ...
Der Container hat eine Komponente erhalten, verloren ...
Fenster schliessen ...
Semantic-Level- Ereignisse werden von den logischen Komponenten der GUI erzeugt. Sie sind aber nicht
spezifisch für bestimmte Komponenten. So können ein Schalter, ein Menüpunkt oder ein List-Objekt ein
ActionEvent erzeugen. Die folgende Tabelle enthält die Semantic-Level- Ereignisse:
Seite 18
4 GUI-Programmierung & Event-Handling
Semantic-Level- Ereignisse
ActionEvent
AdjustmentEvent
ItemEvent
TextEvent
Beschreibung
Ein Kommando ausführen.
Ein Wert wurde angepasst.
Der Zustand eines Eintrags hat sich geändert.
Ein Text hat sich geändert.
4.3.3 Quellen von Ereignissen
Die von einem Objekt erzeugten Ereignisse werden durch die setxxListerner- bzw. addxxListenerMethoden bestimmt.
Alle AWT-Ereignisse unterstützen das multi-cast- Modell. Es gibt keinerlei Informationen darüber, in welcher
Reihenfolge die einer Quelle zugeordnete Beobachter über das Auftreten des Ereignisses benachrichtigt werden.
Garantiert ist nur, dass jeder Bearbeiter eine Kopie des Original-Ereignisses erhält.
Quellen für Low-Level- Ereignisse
Ereignis-Quellen
Component
Container
Dialog
Frame
Methoden für die Erzeugung der Ereignisse
addComponentListener
addFocusListener
addKeyListener
addMouseListener
addMouseMotionListener
addContainerListener
addWindowListener
addWindowListener
Quellen für Semantic-Level- Ereignisse
Ereignis-Quellen
Button
Choice
Checkbox
CheckboxMenuItem
List
MenuItem
Scrollbar
TextArea
TextField
Methoden für die Erzeugung der Ereignisse
addActionListener
addItemListener
addItemListener
addItemListener
addActionListener
addItemListener
addActionListener
addAdjustementListener
addTextListener
addActionListener
addTextListener
4.3.4 Beobachter von Ereignissen
Im Prinzip hat ein EventListener- Schnittstelle für jeden Ereignistyp eine spezielle Methode. Aus Gründen
der Übersichtlichkeit sind manchmal verschiedene Methoden zu einer einzigen Methode zusammengefasst.
Die Schnittstellhierarchie der Low-Level- und Semantic-Level- Beobachter wird in den nachfolgenden
Abbildungen dargestellt:
Seite 19
4 GUI-Programmierung & Event-Handling
Schnittstellen der Low-Level- Beobachter
java.util.EvenListener
java.awt.event.ComponentListener
java.awt.event.ContainerListener
java.awt.event.FocusListener
java.awt.event.KeyListener
java.awt.event.MouseListener
java.awt.event.MouseMotionListener
java.awt.event.WindowListener
Schnittstellen der Semantic-Level- Beobachter
java.util.EvenListener
java.awt.event.ActionListener
java.awt.event.AdjustmentListener
java.awt.event.ItemListener
java.awt.event.TextListener
4.3.5 Adapter
Die Schnittstellen verlangen von einer Klasse eine vollständige Implementierung, auch wenn man nicht alle
Typen von Ereignissen bearbeiten will. Abhilfe schaffen hier die sog. Adapter-Klassen, die für jeden Typ eine
vordefinierte Routine beinhalten. Damit meldet man zur Bearbeitung z.B. der Maus-Ereignisse Sub-Klasse von
MouseAdapter an. Wenn man jetzt nur das MousePressed- Event bearbeiten will, überschreibt man nur die
entsprechende Methode.
Adapter Klassen im AWT
Es gibt nur Adapter-Klassen für Low-Level- Ereignisse, da die Schnittstellen für Semantic-Level- Ereignisse
jeweils nur eine Methode besitzen. Die komplette Aufstellung aller Adapter-Klassen und die Pflichten der
xxListener- Schnittstellen befinden sich im Jobst-Buch.
Die Adapter-Klassenhierarchie wurde in der nachfolgenden Abbildung dargestellt.
java.util.EvenListener
java.awt.event.ComponentAdapter
java.awt.event.FocusAdapter
java.awt.event.KeyAdapter
java.awt.event.MouseAdapter
java.awt.event.MouseMotionAdapter
java.awt.event.WindowAdapter
Praktische Anwendungen
Bei der Programmierung muss man für jeden Bearbeiter eine Subklasse der Adapterklasse schreiben. Der
eleganteste Weg hierzu sind die inneren Klassen. Wenn ein Frame etwa nur das Ereignis windowClosing
bearbeiten will, muss nur die entsprechende Routine überschrieben werden.
Bespiel: Window- Ereignisse bearbeiten
import java.awt.*;
import java.awt.event.*;
Seite 20
4 GUI-Programmierung & Event-Handling
public class Frame2 extends Frame {
Frame2 (String Title) {
super(Title);
setSize(300, 200);
setVisible(true);
addWindowListener(new MyWindowAdapter());
}
class MyWindowAdapter extends WindowAdapter {
public void windowClosing(WindowEvent event) {
System.exit(0);
}
}
public static void main (String[] args) {
new Frame2("1. Frame");
}
}
Hinweis
Im obigen Beispiel wird die innere Klasse „MyWindowAdapter“ definiert, welche von der Adapterklasse
WindowAdapter abgeleitet ist. In dieser Klasse wird die Methode windowClosing mit der Anweisung
System.exit(0) überschrieben, damit das Fenster per Knopfdruck geschlossen werden kann.
Zusätzlich werden Frame2 und ein Exemplar vom MyWindowAdapter als Quelle bzw. als Beobachter von
Fensterereignissen definiert. Dies wird durch
addWindowListener(new MyWindowAdapter());
zum Ausdruck gebracht. Hierdurch werden die Fensterereignisse im Frame2 erzeugt und für die Bearbeitung
zum Exemplar der Klasse MyWindowAdapter gesendet.
4.4 Elementare Controls in Benutzeroberfläche
Dieser Abschnitt soll die elementaren Aspekte der Controls für die Perspektive der Implementierung
beschreiben. Diese Controls werden als Steuerelement in der grafischen Benutzeroberfläche benutzt und wurden
im Kapitel 4.1.3 (Elementare Controls und ihre Einbindung) kurz eingeführt.
In den folgenden Kapiteln werden die Grundfunktionalitäten der Controls besprochen. Dazu sind jeweils ein
Programm sowie dessen Anzeige am Bildschirm angegeben.
4.4.1 Zeichenflächen: Canvas
Canvas ist ein rechteckiges Fenster mit der Basisfunktionalität für Zeichenflächen. Wenn in ein CanvasObjekt gezeichnet werden soll, muss die Methode „paint()“ überschreiben werden. Diese Methode wird vom
Laufzeitsystem (runtime) aufgerufen, sofern ein vollständiger Neuaufbau des Fensters erforderlich ist. Die
Methode „repaint()“ hat dieselbe Wirkung, aber sie kann ausdrücklich von einem Programm aufgerufen
werden.
Das Laufzeitsystem versorgt die Methode paint mit einem Graphics- Objekt als Parameter. Dieses Objekt
liefert den Bezug zum grafischen Kontext der Umgebung und kann für die Ausgabe von Formen und Text
benutzt werden. Die Grafik bezieht sich auf den Bildschirm, genauer gesagt auf die Canvas zugeteilte
Teilfläche des Bildschirms.
Die Klasse Graphics ist recht umfangreich, aber eine Zusammenfassung ist im folgenden Schema gegeben:
Seite 21
4 GUI-Programmierung & Event-Handling
Einige Methoden der Klasse Graphics
clearRect(int x, int y, int width, int height)
copyArea (int x, int y, int width, int height, int dx, int dy)
drawChars(char [] data, int offset, int length, int x, int y)
drawLine (int x1, int y1, int x2, int y2)
drawOval (int x, int y, int width, int height)
drawRect (int x, int y, int width, int height)
drawstring(String str, int x, int y)
fillOval (int x, int y, int width, int height)
fillRect (int x, int y, int width, int height)
setColor (Color c)
setFont (Font f)
// und 38 weitere
Die fünf Methoden zum Zeichen (draw...) sind die Gebräuchlichsten und ermöglichen die Anzeige von
Formen und Text. Die Parameter x und y sind Pixel-Werte, die von der oberen linken Ecke des Bildschirms aus
berechnet werden. Breite und Höhe werden ebenfalls in Pixel angegeben. clearRect löscht einen Teil des
Bildschirms und copyArea kopiert einen Ausschnitt an eine andere festgelegte Stelle, die (dx, dy) entfernt ist.
Die Methoden setColor und setFont können das Erscheinungsbild der Zeichnung anpassen.
Color ist eine Klasse, die Konstanten für die 13 gebräuchlichsten Farben sowie Möglichkeiten zum erstellen
neuer Farben enthält. Die folgenden Farben stehen zur Verfügung: Schwarz, Blau, Zyan, Dunkelgrau, Grau,
Grün, Hellgrün, Magentarot, Orange, Rosa, Rot, Weiss und Gelb.
Alle Angaben erfolgen in Pixel. Die x-Koordinate läuft von links nach rechts, die y-Koordinate von oben nach
unten, wie es bei pixelorientierten Darstellungen üblich ist.
(0, 0)
x
y
Programmbeispiel
import java.awt.*;
import java.awt.event.*;
class FlagCanvas extends Canvas {
String country;
Color bar1, bar2, bar3;
FlagCanvas(String country, Color bar1, Color bar2, Color bar3) {
this.country = country;
this.bar1 = bar1;
this.bar2 = bar2;
this.bar3 = bar3;
}
Seite 22
4 GUI-Programmierung & Event-Handling
public void paint (Graphics g) {
// Draw the flag with the colored rectangles
g.setColor (bar1);
g.fillRect (40, 20, 200, 40);
g.setColor (bar2);
g.fillRect (40, 60, 200, 40);
g.setColor (bar3);
g.fillRect (40, 100, 200, 40);
g.setColor (Color.black);
g.drawString(country, 100, 160);
}
}
public class CanvasDemo extends Frame {
CanvasDemo () {
setSize(300, 200);
add (new FlagCanvas("Germany", Color.black, Color.red,
Color.yellow));
addWindowListener(new MyWindowAdapter());
setVisible(true);
}
class MyWindowAdapter extends WindowAdapter {
public void windowClosing(WindowEvent event) {
System.exit(0);
}
}
public static void main (String [] args) {
new CanvasDemo();
}
}
Hinweis
In diesem Beispiel wird die Klasse „FlagCanvas“ definiert, welche von der Klasse Canvas abgeleitet ist.
Dies wird durch
class FlagCanvas extends Canvas
zum Ausdruck gemacht. Diese Klasse ermöglicht Flaggen mit demselben Muster wie die deutsche Flagge zu
zeichnen, also drei Querbalken in verschiedene Farben. Die Farben der Querbalken können beim Erzeugen der
Flagge an die Klasse übergeben werden. Die Methode paint bezieht sich auf diese Parameter um die Flagge
auf dem Bildschirm auszugeben.
Zusätzlich wird hier die Klasse „CanvasDemo” definiert, welche von der Klasse Frame abgeleitet ist. Im
Konstruktor CanvasDemo wird eine Instanz der Klasse FlagCanvas erzeugt und zu dem Fenster hinzugefügt.
Dies wird durch
add (new FlagCanvas("Germany", Color.black, Color.red, Color.yellow));
zum Ausdruck gemacht. Anschliessend wird in der Methode main ein Objekt der Klasse CanvasDemo
erzeugt. Damit wird das Fenster mit der deutschen Flagge auf dem Bildschirm sichtbar.
Seite 23
4 GUI-Programmierung & Event-Handling
Ausgabenmöglichkeit
4.4.2 Schalter: Button
Ein Button ist eine Fensterfläche mit der Funktionalität eines Schalters mit Text. Wenn der Schalter gedrückt
wird, sendet Java ein Exemplar von einem Ereignis des Typs ActionEvent an den Button. Alle mit
addActionListener bei dem Button registrierten Beobachter erhalten eine Kopie dieses Ereignisses.
Die Methode getActionCommand des Ereignisses liefert den Text des Schalters. Die Methode getSource
der Basisklasse EventObject von ActionEvent liefert das Objekt, welches das Ereignis ausgelöst hat.
Zur Reaktion auf das Ereignis „Schalter gedrückt“ kann es erforderlich sein, den gedrückten Schalter zu
ermitteln. Hierzu kann man für jeden Schalter eine eigene Instanz eines ActionListeners registrieren. Wenn
man nur einen Beobachter für alle Schalter registrieren will, muss dieser anhand des zugestellten Ereignisses den
gedrückten Schalter lokalisieren.
Wenn der Text des Schalters eindeutig ist, kann er in der Reaktion auf das durch das Drücken des Schalters
ausgelöste Ereignis als Identifikation dienen. In diesem Fall erspart man sich die Probleme mit der
Aufbewahrung der Instanzvariablen des Schalters.
// Somewhere
add (new Button ("OK"));
// ActionEvent
if ("OK ".equals(event.getActionCommand()))
// OK has been pressed. Code here the reaction.
}
Wenn diese Eindeutigkeit nicht gegeben ist, kann im Java-Programm jede Instanz eines Schalters aufbewahren
werden. In der Reaktion auf ein Ereignis fragt man dann die Instanzen der Schalter der Reihe nach durch, bis der
gedrückte Schalter gefunden wurde.
// In the class, which treats the events
Button OKButton = new Button ("OK");
add (OKButton); // not for BorderLayout
// ActionEvent
if (OKButton == event.getSource()) {
// OK has been pressed. Code here the reaction.
}
Programmbeispiel
import java.awt.*;
import java.awt.event.*;
Seite 24
4 GUI-Programmierung & Event-Handling
public class ButtonDemo extends Frame implements ActionListener {
ButtonDemo (String Title) {
super (Title);
setLayout (new FlowLayout());
setSize (250, 160);
for (int i = 1; i <= 5; i++) {
Button b = null;
add (b = new Button ("Button " + i));
b.addActionListener(this);
}
addWindowListener (new WindowAdapter () {
public void windowClosing (WindowEvent event) {
System.exit(0);
};
});
setVisible(true);
}
public void actionPerformed(ActionEvent event) {
System.out.println("Button \"" + event.getActionCommand() +
"\" has been pressed!");
}
public static void main (String [] args) {
new ButtonDemo ("Button-Demo");
}
}
Hinweis
In der for- Schleife des Konstruktors „ButtonDemo“ werden 5 Schalter mit verschiedenen Texten erzeugt und
zu dem Fenster hinzugefügt. Zusätzlich werden die 5 Schalter als Quelle und ButtonDemo als Beobachter von
Aktionsereignissen („ActionEvent“) definiert. Dies wird durch
add(b = new Button ("Button " + i));
b.addActionListener(this);
zum Ausdruck gebracht.
Als Beobachter muss ButtonDemo die Methode „actionPerformed()“ der Schnittstelle
„ActionListener“ implementieren. Mit dieser Methode wird hier der Text des gedruckten Schalters auf der
Konsole ausgegeben.
Als Im obigen Beispiel werden zusätzlich ButtonDemo und ein Exemplar vom WindowAdapter als Quelle
bzw. als Beobachter von Fensterereignissen definiert. Dies wird durch
addWindowListener (new WindowAdapter () {
public void windowClosing (WindowEvent event) {
System.exit(0);
};
});
zum Ausdruck gebracht. Als Hier wird die Methode windowClosing der Adapterklasse WindowAdapter
vor dem Erzeugen des Klassenexemplars überschrieben.
Seite 25
4 GUI-Programmierung & Event-Handling
GUI-Anzeige in AWT
Textausgabe nach Drücken von Schalter 1, 2, 3, 4, 5
Button
Button
Button
Button
Button
"Button
"Button
"Button
"Button
"Button
1"
2"
3"
4"
5"
has
has
has
has
has
been
been
been
been
been
pressed!
pressed!
pressed!
pressed!
pressed!
4.4.3 Auswahl
Die Choice- Klasse in AWT liefert eine Auswahlmöglichkeit aus Texten in einem Pop-Up- Menü. Die aktuelle
Auswahl lässt sich programmieren und wird in der Titelzeile des Controls angezeigt. „addItem()“ dient zum
Hinzufügen von Texten in der Auswahl, und „select()“ zur programmierten Auswahl.
Wenn der Anwender einen Eintrag ausgewählt hat, wird ein Exemplar des Typs „ItemEvent“ gesendet.
getItem liefert den auslösenden Eintrag.
Programmbeispiel
import java.awt.*;
import java.awt.event.*;
public class ChoiceDemo extends Frame implements ItemListener{
ChoiceDemo (String Title) {
super (Title);
Choice choice = new Choice();
for(int i = 1; i <= 5; i++){
choice.addItem("Choice " + i);
}
choice.select(1);
choice.addItemListener(this);
add(choice, BorderLayout.NORTH);
addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent event){
System.exit(0);
}
});
setSize(400, 200);
setVisible(true);
}
Seite 26
4 GUI-Programmierung & Event-Handling
// Responsibility as Item-Listener
public void itemStateChanged(ItemEvent event){
System.out.println("Choice " + event.getItem());
}
public static void main (String[] args) {
new ChoiceDemo("Choice-Demo");
}
}
Hinweis
Im Konstruktor von „ChoiceDemo“ wird ein Exemplar von der Auswahl „Choice“ erzeugt. Anschliessend
werden in der for- Schleife mit der Methode addItem die Texte in die Auswahl hinzugefügt. Mit der
Methode select wird der Eintrag von Position 1 selektiert.
Zusätzlich werden die Auswahl choice und die Klasse ChoiceDemo als Quelle bzw. als Beobachter von
Auswahlereignissen („ItemEvent“) definiert. Dies wird durch
choice.addItemListener(this);
explizit zum Ausdruck gebracht.
Als Beobachter muss ChoiceDemo die Methode „itemStateChanged()“ der Schnittstelle
„ItemListener“ implementieren. Mit dieser Methode wird hier der auslösende Eintrag auf der Konsole
ausgegeben.
GUI-Anzeige in AWT
Textausgabe nach den Auslösungen von den Einträgen 1, 2, 3, 4, 5
Choice:
Choice:
Choice:
Choice:
Choice:
Choice
Choice
Choice
Choice
Choice
1
2
3
4
5
4.4.4 Checkbox und Radiobutton
In AWT kann man mit der Klasse Checkbox sowohl Checkboxen als auch Radiobuttons implementieren.
Eine Checkbox in AWT
add (new Checkbox ("Label", null, true));
Seite 27
4 GUI-Programmierung & Event-Handling
Eine Gruppe von Radiobuttons in AWT
CheckboxGroup group = new CheckboxGroup();
add (new Checkbox ("red",
group, true));
add (new Checkbox ("green", group, false));
add (new Checkbox ("blue", group, false));
Wenn der Anwender auf eine Checkbox bzw. einen Radiobutton in der Gruppe klickt, wird das Java-System die
Markierung hierauf setzen bzw. lassen. In allen anderen Mitgliedern der Gruppe wird die Markierung
zurückgesetzt. Alle beim Control mit addItemListener registrierte Beobachtern erhalten einen
ItemEvent.
Programmbeispiel
import java.awt.*;
import java.awt.event.*;
public class CheckboxDemo extends Frame implements ItemListener {
private final static int N = 5;
CheckboxDemo (String Title){
super (Title);
// GridLayout with 2 lines and 5 columns
setLayout(new GridLayout(2,N));
setSize(560, 100);
Checkbox c = null;
// Independent Checkbox
for(int i = 1; i <= N; i++){
add(c = new Checkbox("Check Box " + i));
c.addItemListener(this);
}
// Grouped Checkbox, which furnishes radio buttons
CheckboxGroup group = new CheckboxGroup();
for(int i = 1; i <= N; i++){
add(c = new Checkbox("Radio Button " + i, group, (i==2)));
c.addItemListener(this);
}
addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent event){
System.exit(0);
}
});
setVisible(true);
}
public void itemStateChanged(ItemEvent event){
System.out.println("Choice: " + event.getItem());
}
public static void main (String[] args) {
new CheckboxDemo("Checkbox-Demo");
}
}
Hinweis
In der ersten for- Schleife des Konstruktors „CheckboxDemo“ werden 5 einzelne Checkboxen mit
Seite 28
4 GUI-Programmierung & Event-Handling
verschiedenen Texten erzeugt und zu dem Fenster hinzugefügt. Zusätzlich werden die 5 Checkboxen und
CheckboxDemo als Quelle bzw. als Beobachter von Auswahlereignissen („ItemEvent“) definiert. Dies wird
durch
for (int i = 1; i <= N; i++) {
add(c = new Checkbox("Check Box " + i));
c.addItemListener(this);
}
zum Ausdruck gebracht. In der zweiten for- Schleife des Konstruktor wird dasselbe für 5 in einer Gruppe
zusammengefasste Checkboxen, welche die Radiobuttons darstellen, durchgeführt.
Als Beobachter muss CheckboxDemo die Methode „itemStateChanged()“ der Schnittstelle
„ItemListener“ implementieren. Mit dieser Methode wird hier die selektierte Checkbox bzw. der selektierte
Radiobutton auf der Konsole ausgegeben.
GUI-Anzeige in AWT
Textausgabe nach den klicken auf die Checkboxen 2 und 4, sowie das Radio Button 4
Choice: Check Box 2
Choice: Check Box 4
Choice: Radio Button 4
4.4.5 Statischer Text
Ein Label ist ein Control zur Anzeige von Text, welcher nur vom Programm verändert werden kann.
Label quantity;
add (quantity = new Label ("Quantity..."));
quantity.setText("1234");
4.4.6 Textfelder
TextComponent ist die Basisklasse für alle Controls, die der Editierung von Text dienen. Es bietet unter
anderem die Methoden „void setText(String text)“ zum Setzen und „String getText()“ zum
Auslesen des aktuellen Textes aus einem Textfeld. Mit String getSelectedText() kann der selektierte
Text ausgelesen werden und mit den Methoden „int getSelectionEnd()“ sowie „int
getSelectionStart()“ können die Grenzen der Selektion ermittelt werden.
TextField
TextField dient der Editierung von einzeiligem Text. Textfelder können mit den Aufrufen:
new TextField("blue");
new TextField("green", 20);
angelegt werden. Die Angabe einer Spaltenbreite in Zeicheneinheiten ist also optional. Dieses Control sendet
eine Instanz der Ereignisklasse „TextEvent“, wenn sich der Wert des Textes ändert. Der Beobachter muss
hierzu die Routine „textValueChanged()“ der Schnittstelle „TextListener“ implementieren. Der
Anwender kann Textbereiche selektieren, ohne dass das Java-Programm darüber in Form eines Ereignisses
informiert wird.
Seite 29
4 GUI-Programmierung & Event-Handling
TextArea
„TextArea“ dient dem Editieren von Textbereichen mit mehreren Zeilen. Ein solches Control erhält bezüglich
der Zeilen und Spalten vom AWT Scrollbars, mit denen der Anwender auf die zu bearbeitenden Abschnitte sich
positionieren kann.
Programmbeispiel
import java.awt.*;
import java.awt.event.*;
public class TextDemo extends Frame implements TextListener {
TextField ta;
// Text line
TextArea tf;
// Text field with several lines
TextDemo (String Title) {
super (Title);
setSize (250, 300);
add (new Label ("Please enter your text:"), BorderLayout.NORTH);
add (tf = new TextField ("Text line......"), BorderLayout.SOUTH);
add (ta = new TextArea ("1\n2\n3\n4\n5\n6\n7\n"),
BorderLayout.CENTER);
tf.addTextListener(this);
ta.addTextListener(this);
addWindowListener (new WindowAdapter () {
public void windowClosing (WindowEvent event) {
System.exit(0);
}
});
setVisible(true);
}
public void textValueChanged(TextEvent event) {
// The event source is a every time a text component
TextComponent t = (TextComponent)event.getSource();
System.out.println ("New content: " + t.getText());
}
public static void main (String [] args){
new TextDemo ("Text-Demo");
}
}
Hinweise
Im Konstruktor von „TextDemo“ werden ein Exemplar von TextField (tf) sowie ein Exemplar von
TextArea (ta) erzeugt und zu dem Fenster hinzugefügt. Dies wird durch
add (tf = new TextField ("Text line......"), BorderLayout.SOUTH);
add (ta = new TextArea ("1\n2\n3\n4\n5\n6\n7\n"), BorderLayout.CENTER);
zum Ausdruck gebracht. Zusätzlich werden diese Textkomponenten und TextDemo als Quelle bzw. als
Beobachter von Textereignissen (TextEvent) definiert. Dies wird durch
tf.addTextListener(this);
ta.addTextListener(this);
zum Ausdruck gebracht.
Seite 30
4 GUI-Programmierung & Event-Handling
Als Beobachter muss TextDemo die Methode „textValueChanged()“ der Schnittstelle
„TextListener“ implementieren. Mit dieser Methode wird hier der neue Inhalt des geänderten Textes auf der
Konsole ausgegeben.
GUI-Anzeige in AWT
4.4.7 Rollbalken
Ein Scrollbar-Control dient dem Anwender zur Auswahl eines Zahlenwertes aus einem vorgegebenen
Bereich. Solche Rollbalken können vertikal bzw. horizontal angeordnet werden.
Der Anwender kann einen Rollbalken durch Klicken auf die Markierung auf bzw. ab bewegen, er kann den
„Schieber“ des Rollbalkens erfassen und bewegen, oder er kann auf die neben dem Schieber liegende Leiste des
Rollbalkens klicken. Die mit „addAdjustmentListener()“ registrierte Beobachter erhalten ein
Anpassungsereignis („AdjustmentEvent“).
Programmbeispiel
import java.awt.*;
import java.awt.event.*;
public class ScrollbarDemo extends Frame implements AdjustmentListener {
private Scrollbar h = null, v = null;
ScrollbarDemo (String Title){
super (Title);
setSize(300, 300);
setLayout(null);
h = new Scrollbar(Scrollbar.HORIZONTAL, 50, 20, 0, 100);
v = new Scrollbar(Scrollbar.VERTICAL, 50, 20, 0, 100);
h.setBounds(50, 50, 150, 30);
v.setBounds(50, 100, 30, 150);
add(h);
add(v);
h.addAdjustmentListener(this);
v.addAdjustmentListener(this);
addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent event){
System.exit(0);
}
});
setVisible(true);
}
Seite 31
4 GUI-Programmierung & Event-Handling
// Responsibilities as Item-Listener
public void adjustmentValueChanged(AdjustmentEvent event){
switch(event.getAdjustmentType()){
case AdjustmentEvent.UNIT_INCREMENT:
case AdjustmentEvent.UNIT_DECREMENT:
case AdjustmentEvent.BLOCK_INCREMENT:
case AdjustmentEvent.BLOCK_DECREMENT:
case AdjustmentEvent.TRACK:
if(event.getSource() == h){
System.out.println("h " + event.getValue());
}else if (event.getSource() == v){
System.out.println("v " + event.getValue());
}
break;
}
}
public static void main (String[] args) {
new ScrollbarDemo("Scrollbar-Demo");
}
}
Hinweise
Im Konstruktor von „ScrollbarDemo“ werden zwei Exemplare von Rollbalken erzeugt und zu dem Fenster
hinzugefügt. Dies wird durch
h = new Scrollbar(Scrollbar.HORIZONTAL, 50, 20, 0, 100);
v = new Scrollbar(Scrollbar.VERTICAL, 50, 20, 0, 100);
h.setBounds(50, 50, 150, 30);
v.setBounds(50, 100, 30, 150);
add(h);
add(v);
zum Ausdruck gebracht. Beim Erzeugen der Rollbalken kann die Orientierung, der Wert, der sichtbare Bereich
sowie der Minimal- und Maximalwert festgelegt werden. Zusätzlich kann die Position relativ zum
übergeordneten Container und die Grösse des Rollbalkens mit der Methode setBounds() gesetzt werden.
In diesem Beispiel werden die Rollbalken und die Klasse ScrollbarDemo als Quelle bzw. als Beobachter von
Anpassungsereignis (AdjustmentEvent) definiert. Dies wird durch
h.addAdjustmentListener(this);
v.addAdjustmentListener(this);
zum Ausdruck gebracht.
Als Beobachter muss ScrollbarDemo die Methode „adjustmentValueChanged()“ der Schnittstelle
„AdjustmentListener“ implementieren. Mit dieser Methode wird hier der geänderte Wert auf der Konsole
ausgegeben.
Seite 32
4 GUI-Programmierung & Event-Handling
GUI-Ausgabe für AWT
TRACK
UNIT_INCREMENT
BLOCK_INCREMENT
4.4.8 Menüs in Java
Frames können in Java mit einer Menüleiste der Klasse MenuBar versehen werden. Die Menüleiste erhält vom
Frame alle sie betreffenden Ereignisse. Aus einem Menü kann vom Anwender ein Punkt ausgewählt werden.
Das Programm wird hiervon mit einem ActionEvent benachrichtigt.
Jedes Java-Menü kann wieder ein Menü enthalten. Dabei kann jeder Eintrag ein gewöhnlicher Menüpunkt, ein
Menüpunkt mit einer Marke oder ein Submenü sein. Das folgende Bild zeigt alle Fälle:
Ansicht eines Menüs
Einbau eines Menüs in einem Frame
Eine Menüleiste wird in einem Frame mit der Methode „setMenuBar()“ eingebaut. Diese Menüleiste kann
eine beliebige Anzahl Menüs enthalten. Jedes von diesen Menüs kann wiederum entweder, Menüpunkte
(MenuItem), Menüpunkte mit einer Marke (CheckboxMenuItem) oder Submenüs (Menu) enthalten.
MenuBar mMenuBar = new MenuBar();
SetMenuBar (mMenuBar);
Menu mMenu = new Menu ("File");
mMenuBar.add (mMenu);
mMenu.add (m_Save = new MenuItem ("Save));
Seite 33
// Only possible with Frame
4 GUI-Programmierung & Event-Handling
Reaktion auf die Nachrichten
Bei der Reaktion auf Nachrichten muss die Quelle gefunden werden. Wenn der Text der Menüeinträge eindeutig
ist, kann er benutzt werden.
Wenn diese Eindeutigkeit der Texte a priori nicht gegeben ist, kann man die Instanzen der Menüeinträge im
Frame aufbewahren. Trifft dann ein Ereignis ein, kann man die getSource()-Methode dazu benutzen, den
Ursprung der Nachricht zu finden. Mann muss der Reihe nach alle Instanzen im Menü mit dem Ziel des
Ereignisses vergleichen, bis man fertig ist oder die Quelle des Ereignisses gefunden hat. Diese Vorgehensweise
ist im nachfolgenden Programm implementiert.
Programmbeispiel
import java.awt.*;
import java.awt.event.*;
public class FrameMenu extends Frame implements ActionListener,
ItemListener {
// References for the event treatments
private MenuItem m_Save, m_Open;
private MenuItem m_Red, m_Lightblue, m_Blue, m_Darkblue;
private CheckboxMenuItem m_Pink;
FrameMenu (String Title){
super (Title);
initializeMenu ();
setSize (300, 200);
addWindowListener (new WindowAdapter () {
public void windowClosing (WindowEvent event) {
System.exit(0);
}
});
setVisible(true);
}
// Search the menu item, which has generated the event
// All the possible sources are treated here
public void actionPerformed (ActionEvent event) {
if (event.getSource() == m_Save) {
System.out.println ("Activation of m_Save");
} else if (event.getSource() == m_Open) {
System.out.println ("Activation m_Open");
} else if (event.getSource() == m_Red) {
System.out.println ("Activation m_Red");
} else if (event.getSource() == m_Lightblue) {
System.out.println ("Activation m_Lightblue");
} else if (event.getSource() == m_Blue) {
System.out.println ("Activation m_Blue");
} else if (event.getSource() == m_Darkblue) {
System.out.println ("Activation m_Darkblue");
}
}
public void itemStateChanged (ItemEvent event) {
String sel = (event.getStateChange() == ItemEvent.DESELECTED) ?
"SELECTED" : "DESELECTED";
System.out.println("m_Pink " + sel);
}
Seite 34
4 GUI-Programmierung & Event-Handling
public void initializeMenu () {
MenuBar mMenuBar = new MenuBar ();
setMenuBar (mMenuBar);
Menu mMenu;
// 1. Under menu : File-Menu
mMenuBar.add (mMenu = new Menu ("File"));
mMenu.add (m_Save = new MenuItem ("Save"));
mMenu.add (m_Open = new MenuItem ("Open"));
// 2. Under menu : Option-Menu
mMenuBar.add (mMenu = new Menu ("Option"));
mMenu.add (m_Red = new MenuItem ("Red"));
mMenu.add (m_Pink = new CheckboxMenuItem ("Pink"));
Menu mSubMenu = new Menu ("Blue tone");
mMenu.add(mSubMenu);
mSubMenu.add (m_Lightblue
= new MenuItem ("Light blue"));
mSubMenu.add (m_Blue = new MenuItem ("Blue"));
mSubMenu.add (m_Darkblue = new MenuItem ("Dark blue"));
// Register this class for the treatments of all events
m_Save.addActionListener (this);
m_Open.addActionListener (this);
m_Red.addActionListener (this);
m_Lightblue.addActionListener (this);
m_Blue.addActionListener (this);
m_Darkblue.addActionListener (this);
m_Pink.addActionListener (this);
m_Pink.addItemListener (this);
}
public static void main (String [] args) {
new FrameMenu ("Menu-Demo");
}
}
Seite 35
5 Applets
5 Applets
5.1 Einführung
Ein Applet ist ein Java-Programm, das innerhalb eines Browsers arbeitet und folglich in einer Web-Seite
auftreten kann. Das Applet läuft auf dem Computer des Anwenders, obwohl es eventuell von weither geladen
wurde. Diese spezielle und nur in Java vorhandene Arbeitsweise ist durch die folgende Kombination von
Faktoren möglich:
•
Java-Programme werden nicht vollständig übersetzt sondern interpretiert. Der Quellcode wird in einen
Zwischencode übersetzt, welcher dann seinerseits interpretiert wird.
•
Die Java Virtual Machine, welche den Zwischencode interpretiert, läuft auf allen Webbrowsern.
Wie schone der Name sagt, sind Applets normalerweise kleine Programme, von denen jedes eine einzige
Aufgabe auf einer einzigen Web-Seite ausführt. Das Integrieren von Applets in eine Web-Seite hat folgende
Vorteile:
•
Die Arbeit wird auf der Maschine ausgeführt, auf der die Ergebnisse benötigt werden, statt die
Ergebnisse dorthin zu senden. Dies mindert die Netzbelastung.
•
Die Maschine des Anwenders kann sich wirklich dem Applet widmen und es viel schneller ausführen,
als eine Partition auf dem Server, auf dem das Applet angesiedelt ist.
•
Anders als bei manchen speziell für das Internet entwickelten Sprachen mit eingeschränkter Rechenund Strukturierungsleistungen stehen alle Möglichkeiten der Programmiersprache Java zur Verfügung.
5.1.1 Die HTML-Seiten
HTML steht für Hyper Text Markup Language. Die Ausführung von Applets erfordert nur elementare
Grundkenntnisse darin. Eigentlich besteht das Schema zur Aktivierung eines Applets nur aus einem einzigen
Tag:
HTML-Tags für ein Applet
<APPLET code = "Name" width = n height = m>
</APPLET>
HTML wird im Modul „Internet Technologien/Embedded Webserver“ ausführlich behandelt.
5.1.2 Appletbeispiel
Eine Viruswarnprogramm soll auf dem Bildschirm ausgegeben werden.
Programmbeispiel
import java.applet.Applet;
import java.awt.*;
public class DemoForApplet extends Applet {
static private final int xCoordinate[] = {50, 110, 170};
static private final int yCoordinate[] = {95, 15, 95};
static private final int line = 18;
static private final int letter = 8;
Seite 36
5 Applets
public void paint(Graphics g) {
g.setColor(Color.red);
g.fillPolygon(xCoordinate ,yCoordinate ,3);
g.setColor(Color.white);
g.setFont (new Font("Helvetica", Font.BOLD, 60));
g.drawString("!", 102, 80);
g.setFont (new Font("Helvetica", Font.BOLD, 15));
g.setColor(Color.black);
g.drawString("W A R N I N G",
8*letter, 7*line);
g.drawString("Possible virus detected", 3*letter, 8*line);
g.drawString("Reboot and run virus",
4*letter, 9*line);
g.drawString("remover software",
6*letter, 10*line);
}
}
Hinweis
Das Programm ist ein Applet. Diese wird durch die Schreibweise
public class DemoForApplet extends Applet
Zum Ausdruck gebracht.
Applets können sich selbst in einer grafischen Umgebung darstellen. Hierzu muss die Methode
„paint(Graphics g)“ angeben werden. Diese Methode wird von der Umgebung des Programms
aufgerufen, wenn ein Neuzeichnen der zugewiesenen Fläche erforderlich ist, also insbesondere bei Beginn eines
Programmlaufes oder bei einer Änderung der Grösse der Zeichenfläche.
Der Parameter Graphics g liefert den Bezug zum grafischen Kontext der Umgebung. Die Grafik bezieht sich
auf den Bildschirm, genauer gesagt auf dem Applet zugeteilte Teilfläche des Bildschirms. Diese Teilfläche hat
eine Breite und eine Höhe. Das Applet kann die Ausdehnung seiner Zeichenfläche über die Methoden
getWidth() bzw. getHeight() ermitteln.
Die Klasse Graphics ist recht umfangreich, aber eine Zusammenfassung wurden im Kapitel 4.4.1 eingeführt.
Einbetten des Applets in ein HTML-Dokument
Der Name der Klasse muss wie folgt in dem HTML-Dokument angegeben werden. Das HTML-Dokument soll in
diesem Beispiel etwa example.htlm heissen.
<title>Demo for Applet </title>
<hr>
<applet code = "DemoForApplet.class" width = 200 height = 100>
<hr>
Programmablauf
Das HTML-Dokument kann mit einem Browser betrachtet werden, der Java unterstützen muss. In Diesem Fall
muss der Browser die Datei example.html laden. Zu Testzwecken kann auch das Programm Appletviewer
aus dem JDK benutzt werden:
Appletviewer DemoForApplet.class
Seite 37
5 Applets
Ausgabenmöglichkeit
5.2 Funktionsweise von Applets
Wenn ein Applet kein Hauptprogramm hat, wie wird es dann gestartet oder angehalten? Gestartet wird es aus
einem Browser (z. B. Netscape oder Explorer) oder dem Applet-Viewer durch das Laufzeitsystem von Java. Die
Java Virtual Machine (JVM) ruft dann zu geeigneten Zeitpunkten eine der vier im folgenden Schema gezeigten
Methoden auf. Alle oder einige dieser vier Methoden sollten von jeder Unterklasse von Applet implementiert
werden.
Applet Methoden
Beschreibung
init()
destroy()
start()
init initialisiert das GUI, welches zum Applet gehört und startet alle Threads
destroy vernichtet das GUI und beendet das Applet
start stösst jedes Mal, wenn das Applet von der Web-Seite aus wieder gestartet wird,
Aktionen wie Animationen an.
stop unterbricht die Aktionen, die durch start angestossen worden sind.
stop()
Die folgende Abbildung zeigt den Zustand von einem Applet, welches vom Webbrowser ausgeführt wird. Wenn
der Browser zum ersten Mal dem Tag für das Applet begegnet, wird die Methode init() anstelle des
Konstruktors aufgerufen. init ist für die erste Einrichtung des Applets, seiner Benutzungsschnittstelle, seiner
Knöpfe und Menüs und möglicher weiterer Steuerungs- Threads verantwortlich. Wenn Dagegen wird die
Methode start() immer dann aufgerufen, wenn die Web-Seite, in der das Applet vorkommt, erneut erscheint.
start könnte zum Beispiel eine angehaltene Animation wieder in Gang setzen.
Constructor
startApp()
init()
destroyApp()
start()
startApp()
destroy()
Garbage collection
stopApp()
stop()
destroyApp()
Seite 38
5 Applets
Wenn Jedes Mal wenn ein Neuzeichnen der zugewiesenen Fläche des Applets erforderlich ist, wie zum Beispiel
nach start, wird die Methode paint() vom Laufzeitsystem aufgerufen. Dann kehrt das Applet in einem
passiven Zustand zurück und wartet, bis etwas passiert. Es gibt zwei Möglichkeiten:
•
Das Applet kann unsichtbar werden, indem der Anwender es aus der Seite im Browser hinausschiebt.
•
Ein normales GUI-Ereignis wie z. B. das Drücken einer Maustaste oder eines Knopfs finden statt.
Wird ein Applet unsichtbar, wird seine stop- Methode aufgerufen, die dazu da ist, eventuelle Animationen etc.
anzuhalten. Wird es wieder sichtbar, so wird start aufgerufen. Alle übrigen Ereignisse werden ganz normal
über die im Originalprogramm neu definierten AWT-Methoden behandelt.
Zum Schluss kann eine destroy- Methode bereitgestellt werden, damit das Applet seine Ressourcen freigibt,
bevor der Viewer endet oder der Browser zu einer anderen Seite kommt.
Programmbeispiel
import java.applet.Applet;
import java.awt.*;
public class DemoForApplet extends Applet {
static private final int xCoordinate[] = {50, 110, 170};
static private final int yCoordinate[] = {95, 15, 95};
static private final int line = 18;
static private final int letter = 8;
public void init() {
System.out.println("init");
}
public void start() {
System.out.println("start");
}
public void paint(Graphics g) {
System.out.println("paint");
g.setColor(Color.red);
g.fillPolygon(xCoordinate ,yCoordinate ,3);
g.setColor(Color.white);
g.setFont (new Font("Helvetica", Font.BOLD, 60));
g.drawString("!", 102, 80);
g.setFont (new Font("Helvetica", Font.BOLD, 15));
g.setColor(Color.black);
g.drawString("W A R N I N G",
8*letter, 7*line);
g.drawString("Possible virus detected", 3*letter, 8*line);
g.drawString("Reboot and run virus",
4*letter, 9*line);
g.drawString("remover software",
6*letter, 10*line);
}
public void stop() {
System.out.println("stop");
}
public void destroy() {
System.out.println("destroy");
}
}
Seite 39
5 Applets
Textausgabe nach dem Starten des Applets:
init
start
paint
Textausgabe nach dem auf der Seite Verschieben des Applets:
stop
Textausgabe nach dem Reaktivieren des Applets:
start
paint
Textausgabe nach dem Verlassen des Applets:
stop
destroy
5.2.1 Speicherung von Applets
Wird ein Applet auf einer Server-Maschine gespeichert. Mann kann von jeder anderen mit dem Internet
verbundenen Maschine über das WWW-Protokoll und seinen Namen oder sein Universal Resource Locator
(URL) auf das Applet zugreifen. Die URL des example wäre zum Beispiel:
https://prof.hti.bfh.ch/fue1/java/example.html
Hier ist die HTML-Datei in einem über das Internet zugänglichen Verzeichnis gespeichert. Die Klassendatei, auf
die sie sich bezieht, muss in demselben Verzeichnis sein, wenn sie den einfachen, im folgenden Tag angegeben
Namen hat:
<applet code = "DemoForApplet.class" width = 200 height = 100>
Befindet sich das Applet in einem anderen Verzeichnis, so muss der Tag seine vollständige URL spezifizieren.
5.2.2 Sicherheit von Applets
Bei der Benutzung von Applets im Internet können Bedenken auftreten, dass ein herunter geladenes Programm
eventuell infiziert ist und das System beschädigen könnte. Java beugt dem mit allen Mitteln vor. Zuerst wird der
auf dem Computer eintreffende Bytecode auf seine Gültigkeit geprüft. Wurde er unterwegs verfälscht, führt die
„Java Virtual Machine“ (JVM) ihn nicht aus. Zweitens führt die JVM keinerlei Operationen aus, die das System
beschädigen könnte. So kann z. B. ein von weither stammendes Applet weder Passworte herausfinden noch
Dateien löschen. Die folgende Tabelle fasst das gesamte Regelwerk zusammen.
Operation
Zugriff auf lokale Dateien
Löschen lokaler Dateien
Anderes Programm
ausführen
Eigenen Namen finden
Mit Host neu verbinden
Mit anderem Host
verbinden
Java-Bibliothek laden
exit aufrufen
Pop-Up- Fenster erstellen
JavaAnwendung
√
√
Applet
im Applet-Viewer
√
Lokales Applet
im Browser
Entferntes Applet
im Browser
√
√
√
√
√
√
√
√
√
√
√
√
√
√
√
√
√
√
√
Seite 40
√
√
5 Applets
Aus dieser Tabelle ergibt sich, dass eine Java-Anwendung ein vollständiges Programm ist und als solches alles
machen kann, was der Computer verlangt. Ein Applet ist etwas ganz anderes: Es unterliegt einer Kontrolle und
den oben genanten Regeln. In einem Applet-Viewer ausgeführte Applets können alles, ausser Dateien löschen.
Laufen sie allerdings in einem Browser, werden ihre Aktivitäten etwas beschnitten.
In einem Browser hält ein Applet nicht an: Es endet erst, wenn die Seite, in der es sich befindet, durch eine
andere ersetzt wird. Also ruft es exit nicht auf und es gibt kein close- Kästchen. Applets sind, wie die
Fallstudie zeigt, nahtlos in Web-Seiten integriert. Dass Applets nichts aus dem lokalen Dateisystem lesen oder in
dieses schreiben können, kann von Nachteil sein. Diese Einschränkung kann der Anwender des Applets jedoch
aufheben, indem er einen speziellen Sicherheitsmanager definiert. Zum Schluss zeigt die letzte Tabellenspalte,
dass für entfernte geladene Applets zusätzliche Einschränkungen gelten, die alle zu ihrem Besten sind.
5.3 Die PARAM- Funktion
Die PARAM- Funktionen erlauben eine Interaktion zwischen Web-Seiten und Applets. PARAM stellt Listen
benannter Parameter im HTML-Dokument bereit, die das Applet mit einer Methode namens getParameter
aus der Klasse Applet lesen kann. Die Parameter sind zwischen den Tag-Klammern <APPLET> und
</APPLET> aufgelistet und jeder Parameter muss die folgende Form haben.
HTML-Parameter
<PARAM NAME = "formal" VALUE = "actual">
NAME weist darauf hin, dass die nachfolgende Zeichenreihe der Name des gesuchten Parameters ist. In
demselben Paar von spitzen Klammern gibt es einen Wert, VALUE, der diesem Parameter zugewiesen wird. Bei
dem Wert handelt es sich ebenfalls um eine Zeichenreihe, aber er kann natürlich auch als Zahl oder als ein
beliebiger anderer geforderter Typ gelesen werden. Eine mögliche Anwendung von PARAM wäre die
Produktpreise von einer Supermarkt auf die Web-Seite zu verlagern, indem man sie folgendermassen spezifiziert:
<PARAM NAME = "garlic" VALUE = "12">
Für den Zugriff auf die Parameter kann die Zeichenreihemethode getParameter wie folgt verwendet werden:
unitCosts[i] = Integer.parseInt(getParamter(items[i]));
Hier ist items[i] eine Zeichenreihe wie etwa „garlic", und getParameter findet den Parameter dieses
Namens und gibt den entsprechenden Wert zurück, hier also die Zeichenreihe "12".
5.3.1 Appletbeispiel für die Währungsumrechnung
Es soll ein Applet entwickelt werden, welches einen Betrag in Schweizer-Franken in eine andere Währung
umrechnet. Dieser Wechsel sollte mit den folgenden Währungen möglich sein: amerikanischer Dollar,
australischer Dollar, kanadischer Dollar, europäisches Euro, japanischer Yen und russische Rubble.
Lösung
Folgende Abbildung zeigt das gewünschte Bildschirmlayout. Der Textfeld „Input amount (CHF)“ (ganz oben)
dient zur Betragseingabe in Schweizer Franken. Mit dem Auswahlkästchen „Currency“ (zweite Zeile) kann die
gewünschte Währung, in der umgewandelt werden muss, gewählt werden. Das Textfeld „Output amount“
(dritte Zeile) dient zur Ausgabe des umgewandelten Betrags. Der Schalter „Convert“ (Ganz unten) aktiviert die
Umrechnung von Schweizer Franken in die gewünschte Währung, und gibt das Ergebnis im Textfeld
„Output amount“ aus. Der Schalter „Reset“ löscht beide Textfelder.
Seite 41
5 Applets
Input amount (CH)
0
Currency
American Dollar
Output amount
0
Convert
Reset
Java-Quellcode
Das Programm sieht folgendermassen aus:
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
public class CurrencyConversion extends Applet implements ActionListener {
// Attribute
private String currency[] = {"American Dollars", "Australia Dollars",
"Canadian Dollars", "European Euro",
"Japanese Yen",
"Russian Rubbles"};
private double conversionRate[] = new double [currency.length];
private TextField inputTextField;
private TextField outputTextField;
private Choice
currencyChoice;
public void init () {
// Read the conversion rates with the PARAM-Functions
for (int i = 0; i < currency.length; i++) {
conversionRate[i] = Double.parseDouble(getParameter(currency[i]));
}
// Set the properties of the application window
setLayout (new GridLayout (4,2));
add(new Label ("Input amount (CHF)"));
inputTextField = new TextField("0");
add(inputTextField);
add(new Label ("Conversion currency"));
currencyChoice = new Choice();
for (int i = 0; i < currency.length; i++) {
currencyChoice.addItem(currency[i]);
}
add(currencyChoice);
add(new Label ("Output amount"));
outputTextField = new TextField("0");
add(outputTextField);
Button button = new Button("Convert");
button.addActionListener(this);
add(button);
Seite 42
5 Applets
button = new Button("Reset");
button.addActionListener(this);
add(button);
}
public void actionPerformed (ActionEvent event) {
if ("Convert".equals (event.getActionCommand())) {
// Read the amount and convert it in to a forain monney
double amount = Double.parseDouble (inputTextField.getText());
double rate
= conversioRate[currencyChoice.getSelectedIndex()];
double output = amount * rate;
outputTextField.setText(Double.toString(output));
}
else {
// Clear all text fields
inputTextField.setText("0");
outputTextField.setText("0");
}
}
}
Die Eigenschaften des Applets werden in der Methode init festgelegt. In diesem Beispiel werden die
verschieden Controls erzeugt und dem Applet „CurrencyConversion“ hinzugefügt. Zusätzlich werden die
Schalter „Convert“ und „Reset“ als Quelle sowie MigrosApplet als Beobachter von Aktionsereignisse
(„ActionEvent“) definiert.
Als Beobachter muss CurrencyConversion die Methode actionPerformed der Schnittstelle
ActionListener implementieren. In dieser Methode wird nach dem Text des gedrückten Schalters ermittelt
und anschliessend die entsprechenden Aufgabe durchgeführt.
Für die Parameterübergabe zwischen der Web-Seite und dem Applet wurde die Zeichenreihemethode
getParameter wie folgt verwendet:
for (int i = 0; i < currency.length; i++) {
conversionRate[i] = Double.parseDouble(getParameter(currency[i]));
}
Hier ist currency[i] eine Zeichenreihe wie etwa "American Dollars", und getParameter findet
den Parameter dieses Namens und gibt den entsprechenden Wert zurück, hier also die Zeichenreihe
"0.80414".
Einbetten des CurrencyConversion - Applets in eiem HTML-Dokument
Der Klassenname und die PARAM- Funktionen müssen wie folgt in dem HTML-Dokument angegeben werden:
<title>
Demo for Currency Conversion
</title>
<APPLET code="CurrencyConversion.class" width = 300 height = 150>
<PARAM NAME="American Dollars" VALUE="0.80414">
<PARAM NAME="Australia Dollars" VALUE="1.15197">
<PARAM NAME="Canadian Dollars" VALUE="1.09099">
<PARAM NAME="European Euro"
VALUE="0.66428">
<PARAM NAME="Japanese Yen"
VALUE="87.8662">
<PARAM NAME="Russian Rubles"
VALUE="23.3402">
</APPLET>
Seite 43
5 Applets
Ausgabe
5.4 Klänge und Bilder
In Java können Klänge und Bilder einfach und wirkungsvoll in ein Programm integriert werden.
5.4.1 Klänge
Das Paket applet enthält ein Interface namens AudioClip, das über drei Methoden verfügt: play, stop
und loop. Die Applet-Methode getAudioClip gibt ein Objekt zurück, das dieses Interface implementiert,
und das abgespielt werden kann. Das Schema ist:
Audioclip: Deklaration und Ausführung
AudioClip name;
name = getAudioClip(getCodeBase(), filename);
name.play();
Die Methode getCodeBase in Applet stellt fest, wo das Applet ausgeführt wird, damit der Klang dort
abgespielt werden kann. Derzeit muss die entsprechende Datei noch eine .au- Datei sein und keine .wayDateien.
Zum Beispiel die Datei „ouch.au“ kann wie folgt abgespielt werden:
AudioClip ouch;
ouch = getAudioClip(getCodeBase(), "ouch.au");
ouch.play();
// Or the short version with an anonymous audio clip
play(getCodeBase(), "ouch.au");
Seite 44
5 Applets
5.4.2 Bilder
Bilder sind aus Pixel bestehende Daten, die in einer Datei gespeichert, über ein Netzwerk weitergegeben oder in
Echtzeit von einem Grafik-Rechner oder einer Videokamera erzeugt werden.
Java hat für Bilder ebenso eine Klasse wie für Audioclips, und um eines zu bekommen, folgt man genau
demselben Schema wie oben, wobei AudioClip durch Image ersetzt wird. Ein Bild könnte folgendermassen
bekommen werden.
Image me;
me = Toolkit.getDefaultToolkit().getImage(getCodeBase(), "bischop.gif");
Die Klasse „Toolkit“ ist die abstrakte Oberklasse aller tatsächlichen Implementierungen des Abstract Window
Toolkit. Toolkit oder auch Toolbox (englisch für „Werkzeugsatz“) ist ein Begriff aus der elektronischen
Datenverarbeitung. Er bezeichnet allgemein eine Sammlung von Bibliotheken, Klassen und Schnittstellen, die
das Erstellen von Computerprogrammen vereinfachen sollen. Die Methode „getDefaultToolkit()“ ruft
den Standard-Toolkit und implementiert somit die abstrakte Klasse Toolkit. Die Methode „getImage“
liefert das Bild, welches im gif format gespeichert worden ist.
Zum Darstellen des Bildes greifen wir in der AWT-Klassen Graphics auf die Methode drawImage zu. Ein
Bild wird nach dem folgenden Schema angezeigt:
Ein Bild anzeigen
g.drawImage(Image imagename, int x, int y, ImageObserver observer);
Die x- und y- Koordinaten geben die obere linke Ecke der Stelle an, an der das Bild auf dem Bildschirm
gezeichnet werden soll. Meistens ist der Browser der Beobachter. In dem Fall wird this als vierten Parameter
verwendet. Z. B.:
g.drawImage(me, 0, 0, this);
Programbeispiel
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
public class ImageDemo extends Applet implements ItemListener {
Image image, imageRohr, imageKaufmann, imageFirouzi;
public void init() {
// Layout
setLayout(null);
// Generate the Choice control element
Choice myChoice;
myChoice = new Choice();
// Java supports TIFF, GIF, JPEG, BMP and PNG formats
myChoice.addItem("Rohr.jpg");
myChoice.addItem("Kaufmann.png");
myChoice.addItem("Firouzi.gif");
myChoice.addItemListener(this);
myChoice.select(0);
// Fix the size of Choice and add it into the container
myChoice.setBounds(0, 0, 300, 20);
add(myChoice);
Seite 45
5 Applets
/* Read the image files */
imageRohr
= Toolkit.getDefaultToolkit().getImage("Rohr.jpg");
imageKaufmann = Toolkit.getDefaultToolkit().getImage("Kaufmann.png");
imageFirouzi = Toolkit.getDefaultToolkit().getImage("Firouzi.gif");
// Choose the default image
image = imageRohr;
setSize(300, 180);
}
public void itemStateChanged (ItemEvent event) {
System.out.println(event.getItem().toString());
if (event.getItem().equals("Beerli.jpg")) {
image = imageRohr;
}
else if (event.getItem().equals("Kaufmann.png")) {
image = imageKaufmann;
}
else {
image = imageFirouzi;
}
repaint();
}
public void paint(Graphics g) {
g.drawImage(image, 0, 20, this);
}
}
Hinweis
Die Eigenschaften des Applets werden in der Methode init festgelegt. In diesem Beispiel wird zuerst der
default Layoutmanager deaktiviert. Anschliessend wird die Auswahl-Komponente „myChoice“ erzeugt und
oben im Applet eingefügt. Zusätzlich werden myCoice und ImageDemo respektiv als Quelle und Beobachter
von Auswahlereignesse definiert. Zuletzt werden die Bilderdateien in den verschieden Formaten mit den der
Methode getImage eingelesen.
Als Beobachter muss ImageDemo die Methode itemStateChanged der Schnittstelle ItemListener
implementieren. In dieser Methode wird nach dem Text des gewählten Auswahlpunktes ermittelt und
anschliessend das entsprechende Bild als default Bild gesetzt.
Die Methode paint gibt die default Bild auf dem Bildschirm aus.
Seite 46
5 Applets
Ausgabe
Seite 47
6 Threads
6 Threads
Threads erlauben verschiedene Aktivitäten gleichzeitig oder quasi gleichzeitig durchzuführen. Ein gutes Beispiel
dafür ist der Vorgang des Lesens der Daten über das Internet, welcher mit einem Threads definiert werden kann.
Damit kann das Programm immer noch auf andere Ereignisse von der Benutzeroberfläche reagieren. Auch wenn
der Prozess des Lesens der Daten wegen mangelnden Daten blockiert ist.
Applets sind zwar keineswegs statische Gebilde, dennoch bringen erst Threads Bewegung in Applets. Threads
können als aktive Elemente dafür sorgen, dass „die Bilder laufen lernen“. Im obigen Applet wird zum Beispiel
eine Schrift zum tanzen gebracht. Dabei wird ein Text in periodischen Abständen ausgegeben. Jeder einzelne
Buchstabe bewegt sich in der y-Richtung (Höhe) hin und her, und die Farben der Buchstaben wechseln sich ab.
In Java können Threads auf zwei Arten definiert werden:
•
Als Unterklasse von Thread
•
Durch Implementierung der Schnittstelle Runnable
Die Klassen, welche die Haupteigenschaften von einem Thread enthalten, können als Unterklasse von Thread
definiert werden. Dagegen müssen GUI-Objekte, welche als Unterklasse irgendwelcher GUI-Klassen definiert
worden sind, die Runnable- Schnittstelle implementieren. Dies ergibt sich aus der Tatsache, dass Java keine
Mehrfachvererbung kennt.
Die wichtigsten Thread- Methoden sind start, run und sleep. Nachdem ein Thread über seinen
Konstruktor erzeugt wurde, muss seine start Methode aufgerufen werden. start veranlasst einen Aufruf von
run, wodurch das Betriebssystem diesen Thread in seiner Liste von wartenden Threads hinzufügt. Nach einer
Zeit erhält er beim Prozessor seine Chance und beginnt selbstständig mit seiner Ausführung.
Die run- Methode ist die eigentliche Thread- Routine und muss überschrieben werden. Sie besteht in der
Regel aus einer Schleife, welche solang läuft, bis irgendwelche Bedingungen erfüllt sind. sleep ist eine
Klassenmethode, welche die angegebene Wartezeit in Millisekunden ausführt.
Programmbeispiel
import java.awt.*;
import java.applet.*;
public class DancingText extends Applet implements Runnable {
private Thread thread;
private boolean stopThread = false;
private static final Color [] Palette = {
Color.black, Color.blue, Color.cyan, Color.darkGray,
Color.gray, Color.green, Color.magenta, Color.orange,
Color.pink, Color.red, Color.white, Color.yellow
};
public void start() {
System.out.println("start");
if (thread == null) {
setSize (360, 80);
thread = new Thread (this);
stopThread = false;
thread.start();
}
}
Seite 48
6 Threads
public void run () {
while (thread != null){
if (stopThread == true)
return;
repaint();
try {
Thread.sleep (200);
} catch (InterruptedException e) {
}
}
}
public void paint(Graphics g) {
System.out.println("paint");
char text[] = {'D','a','n','c','i','n','g',' ','T','e','x','t'};
int height = 40;
int width = 20;
g.setFont (new Font("Helvetica", Font.BOLD, 20));
for (int i = 0; i < text.length; i++) {
int start = (int)Math.round (20 * Math.random ());
g.setColor (Palette[start % Palette.length]);
g.drawChars (text, i, 1, i * width, height + start);
}
}
public void stop() {
System.out.println("stop");
stopThread = true;
thread = null;
}
}
Hinweise
Das Programm ist ein Applet, welches eine Thread implementiert. Dies wird durch die Schreibweise
public class DancingText extends Applet implements Runnable
Zum Ausdruck gebracht.
Im obigen Beispiel verhält sich DancingText als ein Thread, indem es die Runnable- Schnittstelle
implementiert. Da DancingText kein Thread ist, benötigt es eine Instanz von Thread. Deshalb wird ein
Thread in der start- Methode erzeugt, welches mit dem Applet durch den Aufruf des Konstruktohrs
thread = new Thread (this);
verbunden wird. Damit kann die run- Methode des Threads als eigener Thread laufen und, wie alle andere
Methoden, auf alle Komponenten von DancingText zugreifen.
Die Art der Anbindung der run- Methode in DancingText ist für jede abgeleitete Klasse erforderlich, da Java
keine Mehrfachvererbung kennt. Diese Technik des „Durchreichens“ von Aufträgen an eine andere Klasse wird
auch als „Delegation“ bezeichnet.
Die run- Methode im obigen Beispiel enthält eine Schleife, in welcher die repaint- Methode nach einer
gewissen Zeitspanne aufgerufen wird. Damit wird in periodischen Abständen das Fenster vollständig neu
aufgebaut.
Seite 49
6 Threads
Skizze zum Ablauf
Stoppe thread
Starte thread
TanzendeSchrift
thread
Zeitachse
Die Threads DancingText und thread sind in der obigen Abbildung gestrichelt dargestellt worden. Am
Anfang initialisiert die init- Methode das Applet und startet dessen Steuerungsthread. Jedes Mal, wenn das
Applet von der Web-Seite aus wieder gestartet wird, generiert start eine neue Instanz von thread. Damit
wird die Animation mit der tanzenden Schrift wieder im Gang gesetzt. Die Aktionen, welche von start
angestossen worden sind, müssen von stop unterbrochen werden. Deshalb werden die erzeugten Threads von
der stop- Methode entsorgt und deren Ressourcen wieder frei gegeben.
Ausgabemöglichkeit
Seite 50
7 Ausnahmen
7 Ausnahmen
7.1 Einführung
Wenn Programme nicht auf Ausnahmesituation reagieren können, führt das zu den von dem Anwendern
gefürchteten Abstürzen. Bei komplexen Programmsystemen und verteilten Anwendungen sind Programme ohne
jede Reaktion auf Ausnahmensituation nicht akzeptabel.
Die Behandlung von Ausnahmen mit den Sprachkonstrukten für den Normalfall hat sich nicht bewährt. So
könnte man sich eine Behandlung von Ausnahmen im Rahmen von Abfragen mit if vorstellen. Jede Routine
müsste dann entsprechende Fehlerschalter bzw. entsprechende Ergebnisse liefern. Bei dieser Vorgehensweise hat
man eine völlig unübersichtliche Programmstruktur erhalten: Eine tiefe Schachtelung nach Aufrufen von
Routinen, eine Verquickung von Programmcode für den Ablauf sowie für den Ausnahmenfall.
Die Anfänge der Behandlung von Ausnahmen wurden mit dem setjmp / longjmp- Konzept von ANSI-C
gelegt. Wegen der inhärenten Sicherheitsdefizite wurde diese Strategie in C++ zu einer strukturierten
Fehlerbehandlung ausgebaut.
In Java wurde von Anfang an die Behandlung von Ausnahmen integriert. Sie ermöglicht eine „weiche“ Landung
nach Fehlern. So können Ausnahmen differenziert behandelt werden. Das Grundkonzept der Behandlung von
Ausnahmen in Java folgt dem Schema:
•
Ausprobieren mit try
•
Auffangen mit catch
•
Auslösen mit throw
7.1.1 Programmbeispiel
import java.lang.ArithmeticException;
public class Test {
public static void main (String[] args) {
for (int i = -3; i < 3; i++) {
try {
System.out.println(1 / i);
} catch (java.lang.ArithmeticException e) {
System.err.println(e);
}
}
}
}
Ausgabe
0
0
-1
java.lang.ArithmeticException: / by zero
1
0
Die Division durch 0 wurde mit dem try-catch- Mechanismus abgefangen. Der Programmlauf wird durch die
Ausnahme nicht abgebrochen, sondern kann kontrolliert durch die Software fortgesetzt werden.
Seite 51
7 Ausnahmen
7.2 Funktionsprinzip
Der Mechanismus der Ausnahmenbehandlung besteht quasi aus einem Wideranlauf des Programms. Mit try
wird eine Art Momentaufnahme des Zustands der Umgebung des Programms gemacht. Diese schliesst den Stack
sowie die Register ein, aber in keinem Fall alle Daten, benutzten Dateien oder Verbindungen mit anderen
Computersystemen. Dann wird der nach try in { ... } angegebene Block betreten. Tritt bei der Abarbeitung
dieses Programmteils eine Programmausnahme auf, sei es explizit oder implizit vom Laufzeitsystem her, wird
der Stack nach catch- Routinen durchsucht, bis eine Passende gefunden wird. Dies gilt auch in
Unterprogrammen, sodass es, bildlich gesprochen, zu einem Zurückrollen des Stacks kommen kann. Dabei sind
folgende Punkte zu beachten:
•
Es kann nur auf Stellen zurückgesprungen werden, die in noch nicht beendeten aufrufenden Methoden
liegen, die auf dem Weg zu throw auch durchlaufen und noch nicht verlassen wurden. Den
try/catch kann nicht mehr als den Stack zurückrollen und Inhalte von Register wiederherstellen.
•
Es werden keine Aktionen des Programms rückgängig gemacht, wie z.B. das löschen einer Datei, das
Stornieren einer Bestellung oder das Abfeuern einer Rakete.
7.2.1 Eine mögliche Implementierung der Ausnahmenbehandlung
Stack
main
Rücksprung
nach Ausnahme
Aufrufkette
7.3 Vorteile der Ausnahmebehandlung in Java
Der Mechanismus der Behandlung von Programmausnahmen in Java erlaubt Programme zu definieren, ohne
dass überall Abfragen auf mögliche Fehlerausgänge vorzusehen sind. Ausserdem gibt es eine klare Trennung
zwischen funktionalem Code (if wird für Steuerung eingesetzt) und dem Code zur Fehlerbehandlung (trycatch bei Fehlerausgang).
Ein weiteren Vorteil der Sprache Java bei der Behandlung von Ausnahmen liegt in der Sicherheit. Im Gegensatz
zu C oder C++ werden alle angelegten Objekte im Rahmen der Garbage Collection automatisch vom
Laufzeitsystem „entsorgt“.
Javaprogramme müssen auf jede Situation gefasst sein, auch auf Ausnahmensituationen. Gerade bei einer
Programmierung für das Internet sind Abstürze von Programmen nicht akzeptabel. Wenn ein Programm nur in
einer „friendly atmosphere“ läuft, ist dies zu wenig. Deshalb muss jede sichere Javaprogrammierung die
Behandlung von Fehlern einschliessen. Damit ist eine „weiche Landung“ nach Programmlauffehlern oder bei
Anwenderfehlern immer möglich.
7.4 Klassen und Ausnahmen
In Java werden die verschiedenen Typen von Programmausnahmen durch eine Klassenhierarchie abgebildet,
welche ihre Wurzel in der Klasse java.lang hat. In dieser Klassenhierarchie werden die diversen
Programmausnahmen durch Klassen modelliert.
Seite 52
7 Ausnahmen
Programme und Programmsysteme können sich der Klassifikation der Ausnahmen in Java anschliessen. Die
Behandlung der Ausnahmen erfolgt dann wieder klassenweise. Im folgenden Beispiel wird eine Basisklasse
Exception1 definiert. Als Spezialfall von Exception1 wird die Klasse Exception2 eingeführt. Die
Methode Demo hat die Aufgabe, verschiedene Programmausnahmen auszulösen.
7.4.1 Programmbeispiel
import java.lang.Exception;
class Exception1 extends Exception {
Exception1 (String text) {
super(text);
}
}
class Exception2 extends Exception1 {
Exception2 (String text) {
super(text);
}
}
public class ExceptionDemo {
void demo (int i) throws Exception1, Exception2, Exception {
if (i == 1) {
throw new Exception1 ("More information 1");
} else if (i == 2) {
throw new Exception2 ("More information 2");
} else if (i == 3) {
throw new Exception ("More information 3");
}
}
public static void main (String [] args){
ExceptionDemo e = new ExceptionDemo ();
for(int i = 1; i <= 4; i++){
try {
e.demo (i);
} catch (Exception2 ex) {
System.out.println (ex);
} catch (Exception1 ex) {
System.out.println (ex);
} catch (Exception ex) {
System.out.println (ex);
} finally {
System.out.println("Final treatment " + i);
}
}
}
}
Ausgabe
1.
2.
3.
4.
5.
6.
7.
Exception1: More information 1
Final treatment 1
Exception2: More information 2
Final treatment 2
java.lang.Exception: More information 3
Final treatment 3
Final treatment 4
Seite 53
7 Ausnahmen
Hinweis
Beachten Sie bitte, dass die for- Schleife im Programm trotz der Programmausnahmen dreimal durchlaufen
wird. Dies ist nur möglich, da die Ausnahmen aufgefangen wurden.
Zeile 1 zeigt, dass die Ausnahme Exception1 von der richtigen Stelle (b) im Programm aufgefangen wird. In
Zeile 2 sieht man die Ausgabe der Abschlussbehandlung für die Programmausnahme mit finally. Mit dieser
Anweisung kann man gemeinsamen Programmcode in verschiedenen catch- Zweigen der
Ausnahmenbehandlungen schreiben, welcher aber auch dann durchlaufen wird, wenn keine Ausnahme vorliegt.
Zeile 3 zeigt die Behandlung der zweiten Ausnahme analog zur ersten Ausnahme. Exception2 ist ein
Spezialfall von Exception1. Wird eine Exception2 geworfen, wird sie als Execption1 behandelt. Zeile
4 enthält die Abschlussbehandlung.
Wenn die Blöcke (a) und (b) im Quellprogramm vertauscht wären, würde sich folgende Situation ergeben:
catch (Exception1 ex)
System.out.println
}
catch (Exception2 ex)
System.out.println
}
{
(ex);
(b)
{
(ex);
(a)
Das so geänderte Programm wird vom Java-Compiler nicht übersetzt, da die Behandlung von Exception1 die
von Exception2 verdecken würde, da immer die erste passende Ausnahmebehandlung zum Auffangen
gewählt wird.
Zeile 5 der Ausgabe des Programms zeigt, dass finally keine Behandlung jeder Ausnahme darstellt, sondern
lediglich der abschliessenden Ausnahmenbehandlung dient. Wenn eine pauschale Behandlung von Ausnahmen
gewünscht wird, fängt man die Oberklasse der Ausnahme Exception auf. Dadurch würde man aber eine
differenzierte Reaktion auf die Fehlersituation verzichten. Zeile 6 zeigt die zugehörige Abschlussbehandlung.
Die Ausgabe der Zeile 7 erfolgt auch ohne Programmausnahme.
Seite 54
8 Ein- und Ausgabe
8 Ein- und Ausgabe
In dem Package „java.io“ bündelt das JDK die Ein-/Ausgabe in Java. Da Java eine Programmiersprache ist,
welche speziell für Anwendungen im Internet entwickelt wurde, müssen Programme in Java mit diversen
Quellen für die Ein-/Ausgabe rechnen: lokale Dateien, Tastatur, Dateien über das Internet. Zur Lösung dieses
Problems
benutzt
man
die
Abstraktionen
„java.io.InputStream“
zum
lesen
und
„java.io.OutputStream“ zum schreiben von Daten. Diese Klassen enthalten die Definitionen aller
Methoden zur grundlegenden Ein-/Ausgabe. Allerdings gibt es keine Exemplare von diesen abstrakten Klassen,
sondern nur Ableitungen davon, wie z.B. die Klasse „java.io.FileInputStream“.
Zur internen Darstellung von Zeichen benutzt Java den Unicode. Dateien oder Datenströme im Internet liegen
dagegen häufig als ASCII-Code vor. Deswegen muss in Java eine Brücke zwischen diesen Welten geschlagen
werden. Zur besseren Unterstützung der Internationalisierung durch den Unicode wurde ab Java 1.1 zusätzlich zu
den Byte-orientierten Stream-Klassen für die Ein-/Ausgabe die Zeichen-orientierten Reader- bzw. WriterKlassen eingeführt.
Die folgende Skizze zeigt die möglichen Richtungen für die Eingabe. Die Ausgabe entspricht diesem Schema mit
umgekehrter Richtung der Verarbeitung:
Bytes
Stream: Bytes
P
r
o
g
r
a
m
m
Reader: char
InputStream
Internet
Daten
DataInput: Daten
Streams arbeiten Byte orientiert ohne Umformung. Reader bzw. Writer arbeiten mit Unicode-Zeichen. Ein
InputStreamReader bzw. OutputStreamWriter schlägt eine Brücke zwischen den Byte- und den
Unicode-orientierten Welten. DataInput bzw. DataOutput Darstellungen verarbeiten die Daten in binären
Formaten für das Internet. So werden die Darstellungen von Zahlen im dualen System, in der im Internet
festgelegte Reihenfolge für die einzelnen Bytes, abgelegt bzw. eingelesen.
8.1 Eingabe in Java
8.1.1 Eingabe mit der byteorientierten Stream-Klassen
Die Klasse InputStream dient als Abstraktion für alle konkret möglichen Eingabeströme. In ihr werden nur
einfachste Funktionen zum sequenziellen Lesezugriff definiert. Man kann einzelne Bytes oder Blöcke von Byte
lesen. Es gibt keinerlei Methoden zur Umformung von Daten. Die wichtigsten Methoden der Klassen
InputStream befinden sich in der nächsten Tabelle:
void close();
int read();
int read(
byte[] cbuf,
int off,
int len);
Schliessen des Streams und Freigabe aller belegten Ressourcen.
Lesen eines Bytes. Das Ergebnis wird als Zahl im Bereich von 0 bis 255
(hexadezimal 0x00 bis 0xff) zurückgeliefert.
Der Wert –1 steht für das Ende der Datei.
Aus dem Eingabestrom werden len Bytes eingelesen und in den Puffer cbuf
ab dem Byte off abgelegt.
Der Wert –1 codiert das Ende der Datei.
Seite 55
8 Ein- und Ausgabe
Die InputStream- Klassenhierarchie ist in der nachfolgenden Abbildung dargestellt. Zur Anwendung wird
jeweils eine Instanz von diesen abgeleiteten Klassen angelegt, die irgendeinen konkreten Eingabestrom benutzt.
java.io.InputStream
java.io.ByteArrayInputStream
java.io.FileInputStream
java.io.ObjectInputStream
java.io.PipedInputStream
java.io.SequenceInputStream
java.io.StringBufferInputStream
javax.sound.sampled.AudioInputStream
java.io.FilterInputStream
java.io.BufferedInputStream
java.io.DataInputStream
java.io.LineNumberInputStream
java.io.PuschbackInputStream
java.security.DigestInputStream
java.util.zip.ChekedInputStream
javas.swing.ProgressMonitorInputStream
java.util.zip.InflaterInputStream
java.util.zip.GZIPInputStream
java.util.zip.ZipInputStream
java.util.zip.jarInputStream
Die Konstruktoren und die Beschreibungen der wichtigsten Klassen, welche von InputStream abgeleitet sind,
befinden sich in der folgenden Tabelle.
ByteArrayInputStream(byte[] buf)
FileInputStream(File file)
PipedInputStream()
StringBufferInputStream(String s)
Mit der Klasse ByteArrayInputStream ist es
möglich, auf ein Byte-Array genauso zuzugreifen, wie auf
einen Eingabe-Stream.
Diese Klasse stellt einen Stream zur Verfügung, mit
welchem Dateien ausgelesen werden können
Mit den Klassen PipedInputStream und
PipedOutputStream können zwei Threads Daten
austauschen, indem Exemplare dieser Klassen verkettet
werden.
Der StringBufferInputStream ermöglicht es, auf
einen String genauso wie auf einen InputStream
zuzugreifen.
Die Parameterliste der obigen Konstruktoren zeigen welche Eingabeströme bei der Instanzierung verwendet
werden können. Zum Beispiel bei der Anlage von einem Objekt der FileInputStream- Klasse kann der
Dateiname als Eingabestrom angegeben werden:
FileInputStream fis = new FileInputStream ("FileName");
8.1.2 Eingabe mit der zeichenorientierten Reader-Klassen
Zur Eingabe von Text in Programme ist im JDK der Weg über die Reader empfohlen, weil dabei die Umsetzung
der Bytes des Eingabestroms in Zeichen gemäss den lokalen Einstellungen erfolgt. Zudem funktioniert die
Eingabe am besten in gepufferter Form. Deshalb sind die wichtigsten Methoden der Klasse BufferedReader
besonders interessant.
Seite 56
8 Ein- und Ausgabe
void close();
int read();
int read(
char[] cbuf,
int off,
int len);
String readLine();
boolean ready();
Schliessen des Streams.
Lesen eines Zeichens. Das Ergebnis wird als Zahl im Bereich von 0 bis 65535
(hexadezimal 0x0000 bis 0xffff) zurückgeliefert.
Der Wert –1 steht für das Ende der Datei.
Aus dem Eingabestrom werden len Zeichen eingelesen und in den Puffer
cbuf ab dem Zeichen mit dem Index off abgelegt. Die Methode gibt die
Anzahl der gelesenen Zeichen zurück.
Der Wert –1 codiert das Dateiende.
Einlesen einer Zeile. Bei Dateiende wird null geliefert.
Anzeige, ob der Eingabestrom bereit zum lesen ist. Dies ist dann der Fall, wenn
der Puffer nicht leer oder der darunter liegende Zeichenstrom bereit ist.
Die Reader-Klassenhierarchie ist in der nachfolgenden Abbildung dargestellt:
java.io.Reader
java.io.CharArrayReader
java.io.PipedReader
java.io.StringReader
java.io.BufferedReader
java.io.LineNumberReader
java.io.FilterReader
java.io.PushbackReader
java.io.InputStreamReader
java.io.FileReader
Die Konstruktoren und die Beschreibung der wichtigsten Klassen, welche von Reader abgeleitet sind, befinden
sich in der nächsten Tabelle:
CharArrayReader(char[] buf)
PipedReader()
StringReader(String s)
BufferedReader(Reader in)
InputStreamReader(InputStream in)
FileReader(String fileName)
CharArrayReader bietet die Möglichkeit, aus einem
char-Array genauso wie aus einem Stream zu lesen
Diese
Klasse
ist
das
Reader-Äquivalent
des
PipedInputStream
Die Klasse StringReader bietet die Möglichkeit, auf
einen String wie auf einen Eingabe-Stream zuzugreifen.
BufferedReader ist ein gepufferter Eingabe-Stream für
Unicode-Zeichen. Dieser Stream arbeitet stets auf einem
anderen Reader-Objekt, aus dem er die Daten bezieht.
InputStreamReader
bietet
die
Möglichkeit,
bytebasierten
InputStreamKlassen
und
die
zeichenbasierten Reader- Klassen zu koppeln.
Diese Klasse stellt einen Stream zur Verfügung, der eine
Datei ausliest. Hierbei werden die gelesenen Bytes aus der
Zeichencodierung der Plattform in Unicode-Zeichen
umgesetzt.
Codebeispiel
Der folgende Programmausschnitt zeigt, wie man einen Reader für Datei erzeugt und die Datei zeilenweise
liest. Dabei ist zu achten, dass dieser Programmschnitt ein java.io.IOException werfen kann.
// Either in the standard way
FileInputStream fis = new FileInputStream("name");
InputStreamReader isr = new InputStreamReader(fis);
BufferedReader br = new BufferedReader(isr);
Seite 57
8 Ein- und Ausgabe
/* or in a nested way
BufferedReader br = new BufferedReader(
new InputStreamReader(
new FileInputStream("name")));
*/
/* or even in the short way with the FileReader class
BufferedReader br = new BufferedReader (
new FileReader("name"));
*/
String s;
while((s = br.readLine()) != null){
// Treat the line s
}
Hinweis
Im obigen Beispiel werden die Instanzen fis, isr und br angelegt. fis ist ein Objekt der Klasse
FileInputStream, welches die Datei „name“ als Eingabestrom verwendet. fis stellt einen Stream zur
Verfügung, mit dem aus name ausgelesen werden kann. isr ist ein Objekt der Klasse InputStreamReader,
welches wiederum fis als Eingabestrom verwendet. Damit können die eingelesenen Bytes in Unicodezeichen
umgewandelt werden. br ist ein Objekt der Klasse BufferedReader, welches erneut isr als Eingabestrom
verwendet. Damit können die Daten in einem Puffer zwischengespeichert werden. Die nachfolgenden
Leseoperationen beziehen ihre Daten aus diesem Puffer, was Geschwindigkeitsvorteile bringen kann.
Mit der Verschachtelung der obigen Instanzen wird ein Datenstrom erzeugt, dessen Quelle die Datei name ist.
Dieser Strom verfügt über alle Attribute und Methoden der Klasse BufferedReader (wie z.B. readLine).
Damit können die einzelne Zeile von der Datei gelesen werden.
8.1.3 Die Standard Eingabe
UNIX und Windows sehen für Anwendungen eine Standard-Eingaberichtung vor. Diese wird oft auch mit
stdin bezeichnet. Java Programme können über das static- Attribut System.in auf diesen
InputStream zugreifen.
Programmbeispiel
Zum Einlesen von Zeichen von Tastatur wird einen InputStreamReader auf den Eingabestrom
System.in angewandt. Mit einem Puffer wird die Eingabe effizienter. Wegen der Komplexität der Eingabe
von Tastatur, empfiehlt sich die Kapselung des Zugriffs, wie im folgenden Beispiel gezeigt:
import java.io.*;
public class MyReadLine {
static BufferedReader b = null;
public static String readln() throws java.io.IOException {
if(b == null){
b = new BufferedReader(
new InputStreamReader(System.in));
}
return b.readLine();
}
Seite 58
8 Ein- und Ausgabe
public static void main (String[] args) throws java.io.IOException {
String s;
while((s = MyReadLine.readln()) != null){
System.out.println (">" + s + "<");
}
}
}
8.2 Ausgabe in Java
8.2.1 Ausgabe mit der byteorientierten Stream-Klassen
Die Basisklasse für Ausgabe ist java.io.OutputStream. Sie bittet aber nur Transferdienste für Daten ohne
jede Umformung an. Die wichtigste angeleitete Klasse ist die PrintStream- Klasse. Diese Klasse enthält die
print(...) bzw. println(...) Methoden für elementare Datentypen sowie für Objekte. Sie ist damit
besonders nützlich, wenn es um die Ausgabe von Daten als Text geht, wie es z.B. bei Ausgabe auf die Konsole
der Fall ist. Falls die Standartcodierung von Zeichen nicht ausreicht, sollte an Stelle eines PrintStreams ein
PrintWriter eingesetzt werden. Beide Klassen enthalten folgende Methoden.
void close();
void write(int c);
int write (
char[] cbuf,
int off,
int len);
void flush();
void print(xx d);
void println(xx d);
Schliessen des Streams und Freigabe aller belegten Ressourcen.
Schreiben des Zeichens in den niederwertigen 16 Bits von c. Die 16
höherwertigen Bits werden ignoriert.
Schreiben von len Zeichen aus dem Feld cbuf ab dem Zeichen mit dem Index
off.
flush soll das System veranlassen, vorher geschrieben Bytes tatsächlich in
den Ausgabestrom zu schreiben. Falls in einer Datei nach Schreibvorgängen
Daten fehlen, ist flush eine gute Wahl.
xx ist einer der elementaren Datentypen, ein String oder ein Objekt. Bei
elementaren Datentypen werden die übergebenen Daten in Text umgewandelt
und
ausgeben.
Ein
Objekt
wird
mit
der
Methode
String.valueOf(Object) in Text umgewandelt und ausgegeben.
Wie print(xx d). Aber es wird zusätzlich eine neue Zeile begonnen.
Die OutputStream -Klassenhierarchie ist in der nachfolgenden Abbildung dargestellt:
java.io.OutputStream
java.io.ByteArrayOutputStream
java.io.FileOutputStream
java.io.ObjektOutputStream
java.io.PipedOutputStream
java.io.FilterOutputStream
java.io.BufferedOutputStream
java.io.DataOutputStream
java.security.DigestOutputStream
java.util.zip.CheckedOutputStream
java.io.PrintStream
java.rmi.server.LogStream
java.util.zip.DeflaterOutputStream
java.util.zip.GZIPOutputStream
java.util.zip.ZipOutputStream
java.util.jar.JarOutputStream
Die Konstruktoren und die Beschreibung der wichtigsten Klassen, welche von OutputStream abgeleitet sind,
befinden sich in der nächsten Tabelle:
Seite 59
8 Ein- und Ausgabe
ByteArrayOutputStream()
FileOutputStream(File file)
PipedOutputStream()
Mit der Klasse ByteArrayOutputStream können
Schreibzugriffe auf ein Byte-Array genauso wie auf einen AusgabeStream erfolgen
Diese Klasse stellt einen Stream zur Verfügung, mit dem Ausgaben in
eine Datei gemacht werden können.
Mit den Klassen PipedInputStream und
PipedOutputStream können zwei Threads Daten austauschen,
indem Exemplare dieser Klassen verkettet werden.
8.2.2 Ausgabe mit der zeichenorientierten Writer-Klassen
Die Writer- Klassenhierarchie ist in der nachfolgenden Abbildung dargestellt:
java.io.Writer
java.io.BufferedWriter
java.io.CharArrayWriter
java.io.FilterWriter
java.io.PipedWriter
java.io.PrintWriter
java.io.StringWriter
java.io.OutputStreamWriter
java.io.FileWriter
Die Konstruktoren und die Beschreibung der wichtigsten Klassen, welche von Writer abgeleitet sind, befinden
sich in der nächsten Tabelle:
BufferedWriter(Writer out)
CharArrayWriter()
PipedWriter()
StringWriter()
OutputStreamWriter(OutputStream out)
FileWriter(String fileName)
BufferedWriter ist ein gepufferter Ausgabe-Stream für
Unicode-Zeichen. Er arbeitet stets auf einem anderen
Writer- Objekt, in das er die Daten schreibt
CharArrayWriter bietet die Möglichkeit, in ein charArray genauso wie in einen Stream zu schreiben.
Die Klasse PipedWriter ist das Writer- Äquivalent des
PipedOutputStream.
Die Klasse StringWriter bietet die Möglichkeit, in einen
String genauso wie in einen Stream zu schreiben.
OutputStreamWriter ist die Basis für Writer-Klassen,
die auf OutputStreams arbeiten.
Diese Klasse stellt einen Stream zur Verfügung, mit dem
Unicode-Zeichen in Dateien geschrieben werden können.
8.2.3 Die Standard-Ausgabe
UNIX und Windows sehen für Anwendungen eine Standard-Ausgaberichtung vor. Diese wird oft auch mit
stdout bezeichnet. Java-Programme können über das static- Attribut System.out auf diesen
PrintStream zugreifen. Für Fehlermeldungen ist dagegen die Ausgangsnachricht stderr, die in Java über
System.err ansprechbar ist, besser geeignet. Denn mit der Umlenkung
java Program > FileName
wird die Ausgabe des Programms nach stdout in die durch „Dateiname“ angegebene Datei umgelenkt, nicht
aber die Ausgabe nach stderr.
8.3 Anwendungs-Beispiele
In diesem Kapitel sollen einige typische Situationen aus der Anwendung der Dateiverarbeitung besprochen
werden. Sie werden mit den Hilfsmitteln gelöst, welche die Bibliothek java.io zur Verfügung stellt.
Seite 60
8 Ein- und Ausgabe
8.3.1 Byteweise Verarbeitung von Dateien
Ein Dateiname soll vom System.in eingelesen werden. System.in ist ein InputStream. Die Datei mit
dem eingegebenen Namen soll geöffnet werden. Danach soll die Datei byteweise gelesen und ausgegeben
werden.
Vorgehen
Zunächst wird der Dateiname eingelesen. Dann wird versucht, eine Datei dieses Namens zu öffnen. Dabei muss
die Programmausnahme java.io.FileNotFoundException behandelt werden, denn die Datei könnte
nicht vorhanden sein. Danach wird die Eingabedatei in der klassischen Schleife bearbeitet:
while (!End of the file(inputFile)) {
Read the Byte as int;
Write the Byte;
}
Jedes Byte muss als int gelesen werden, um die EOF-Kennung –1 (End Of File) verarbeiten zu können: Da ein
Byte alle Werte von 0 bis 255 annehmen kann, könnte in den 8 Bit des Bytes die EOF-Kennung nicht
verschlüsselt werden. Beim lesen der Datei sowie beim Schliessen müssen die möglichen
java.io.IOException- Ausnahmen bearbeitet werden.
Das Programm gibt alle Anfragen nach System.err aus. Dadurch kann man das Programm auch zum
Kopieren von Dateien verwenden, wenn man es in folgender Form aufruft. Der Name der Ausgangsdatei wird
angefordert, das Ergebnis wird in die Datei „DestinationFile“ gespeichert.
java ReadFileBytes > DestinationFile
Programmbeispiel
import java.io.*;
public class ReadFileBytes {
public static void main (String args[]) {
// Read the file name
System.err.print("File name?: ");
String Filename = null;
try {
Filename = MyReadLine.readln();
} catch (IOException e) {
System.err.println(e);
return;
}
System.err.println("File name " + Filename);
// Open the file.
// Be careful, the given file could not exist!
FileInputStream f = null;
try {
f = new FileInputStream(Filename);
} catch (FileNotFoundException e) {
System.err.println("File " + Filename + " has not been found!");
return;
}
Seite 61
8 Ein- und Ausgabe
// Read the file contains
int ch;
try {
while ((ch = f.read()) != -1) {
System.out.write(ch);
}
f.close();
} catch (IOException e) {
System.err.println(e);
return;
}
}
}
8.3.2 Blockweise Verarbeitung von Daten
Eine Datei soll binär kopiert werden. Sie darf nicht auf sich selbst kopiert werden, denn wenn sie vor dem ersten
Lesen zum Schreiben geöffnet würde, wäre der Inhalt gelöscht. Vor Überschreiben einer vorhandenen Datei soll
beim Anwender um eine ausdrückliche Bestätigung angefragt werden. Alle Programmausnahmen bei der Ein/Ausgabe sollen abgefangen werden.
Vorgehen
Es soll ein FileInputStream bzw. ein FileOutputStream benutzt werden. Damit wird eine binäre
Kopie von Dateien möglich. Es ist effizienter, eine Datei blockweise zu bearbeiten. Die Namen der Quell- und
der Zieldatei sollen in der Kommandozeile übergeben werden. Wenn eine Datei auf sich selbst kopiert wird, führt
dies bei vielen Systemen zum löschen der Datei. Um dies zu vermeiden, muss auf Gleichheit der Namen der
Quell- bzw. der Zieldatei abgefragt werden. Mansche Betriebssysteme ignorieren Unterschiede bei der Grossbzw. Kleinschreibung von Dateinamen. Java bietet einen Vergleich von Strings an, der dies ignoriert.
Mit der File- Klasse kann man prüfen, ob die Zieldatei vorhanden ist. Wenn dies der Fall ist, wird beim
Anwender angefragt, ob die Datei wirklich überschreiben werden soll. Wenn der Anwender des Programms im
Aufruf die Argumente Quelle und Ziel verwechselt, würde mit dieser Abfrage die automatische Überschreibung
einer Datei verhindert.
Nach dieser umfangreichen Vorbereitung kann in einer read-write- Schleife kopiert werden.
Programmbeispiel
import java.io.*;
public class TreatFileBlock {
final public int BUFSIZE = 80;
public void copy (String Source, String Destination) {
FileInputStream Input = null;
FileOutputStream Output = null;
if (Source.equalsIgnoreCase(Destination)) {
System.err.println("Error: fill will be copied into himself");
// Windows needs ignore case
return;
}
Seite 62
8 Ein- und Ausgabe
File file = new File (Destination);
if(file.exists()) {
System.out.print("File " + Destination +
" exists. Over write? (Y/N): ");
System.out.flush();
try {
char ch = (char)System.in.read();
if(Character.toUpperCase(ch) != 'Y') {
return; // Break in case of doubt
}
} catch(IOException e) {
return;
}
}
try {
Input = new FileInputStream(Source);
} catch(FileNotFoundException e) {
System.err.println("Error : Source file " + Source +
" could not be found");
}
try {
Output = new FileOutputStream(Destination);
} catch (FileNotFoundException e) {
try {
Input.close();
} catch (IOException e1) {
System.err.println("Error : can not close the file " +
Destination);
return;
}
System.err.println("Error : can not close the file " +
Source);
return;
}
int nbytes = -1;
byte b[] = new byte[BUFSIZE];
try {
while ((nbytes = Input.read(b, 0, BUFSIZE)) != -1) {
Output.write(b, 0, BUFSIZE);
}
} catch(IOException e) {
System.err.println("Error during the copy process");
return;
}
}
public static void main(String[] args) {
if(args.length != 2) {
System.err.println("Call TreatFileBlock: Source and Destination");
System.exit(1);
}
TreatFileBlock tfb = new TreatFileBlock ();
tfb.copy(args[0], args[1]);
}
}
8.3.3 Daten im Format für das Internet verarbeiten
Das Format der Daten für das Internet soll besprochen werden. Wichtige Routinen zum Schreiben auf der einen
Seite und zum Lesen auf der anderen Seite sollen behandeln werden. Das Beispiel kann nicht dazu dienen, Daten
Seite 63
8 Ein- und Ausgabe
in der Textdarstellung ein bzw. auszugeben.
Vorgehen
Die Klasse DataInputStream implementiert die DataInput- Schnittstelle zur Eingabe von Daten. Die
Daten werden dabei umgeformt. In der Datei müssen z.B. Zahlen im Internet-Format vorliegen. Damit ist ein
Austausch von Daten auch mit Programmen möglich, die in C oder anderen Programmiersprachen geschrieben
wurden, sofern die Daten dort in das entsprechende Format umgesetzt werden. Die Daten liegen dann in einem
Format vor, das nicht vom Rechner abhängt.
Programmbeispiel
import java.io.*;
public class IODemo {
// Write the binary data into the file Data.txt
void testOutput() {
try {
DataOutputStream out = new DataOutputStream(
new FileOutputStream("Data.txt"));
out.writeBoolean (true);
out.writeByte
(1);
out.writeChar
('a');
out.writeDouble (1.0);
out.writeFloat
(1.0f);
out.writeInt
(1000);
out.writeLong
(2000l); // not 20001, but 2000l
out.writeShort
(300);
out.writeBytes
("writeBytes");
} catch (IOException e) {
System.err.println(e);
}
}
// Write the binary data with their type name into the file Data.txt
void testOutputText() {
try {
DataOutputStream out = new DataOutputStream(
new FileOutputStream("Data.txt"));
out.writeBytes ("Boolean") ; out.writeBoolean (true);
out.writeBytes ("Byte")
; out.writeByte
(1);
out.writeBytes ("Char")
; out.writeChar
('a');
out.writeBytes ("Double") ; out.writeDouble (1.0);
out.writeBytes ("Float")
; out.writeFloat
(1.0f);
out.writeBytes ("Int")
; out.writeInt
(0x12345678 );
out.writeBytes ("Long")
; out.writeLong
(2000l);
out.writeBytes ("Short")
; out.writeShort
(300);
} catch (IOException e) {
System.err.println(e);
}
}
Seite 64
8 Ein- und Ausgabe
/* Read the binary data from the file Data.txt,
and write its contents on the screen */
void testInput () {
try {
DataInputStream in = new DataInputStream(
new FileInputStream("Data.txt"));
System.out.println (in.readBoolean());
System.out.println (in.readByte());
System.out.println (in.readChar());
System.out.println (in.readDouble());
System.out.println (in.readFloat());
System.out.println (in.readInt());
System.out.println (in.readLong());
System.out.println (in.readShort());
byte [] Bytes = new byte [100];
int ibytes = in.read(Bytes, 0, Bytes.length -1);
System.out.println(ibytes + ">" +
new String (Bytes, 0, ibytes -1) + "<");
} catch (IOException e) {
System.err.println(e);
}
}
public static void main (String[] args) {
if (args.length == 0) {
System.err.println ("Call IODemo: (read|bin|text)");
System.exit(1);
}
IODemo iodemo = new IODemo ();
if (args[0].equalsIgnoreCase ("bin"))
iodemo.testOutput ();
if (args[0].equalsIgnoreCase ("text"))
iodemo.testOutputText ();
if (args[0].equalsIgnoreCase ("read"))
iodemo.testInput ();
}
}
Seite 65
Index
Index
<
byteorientierte Stream-Klasse
..........................................55
</APPLET> ........................42
<APPLET>...........................42
C
A
Abstract Windows Toolkit .....4
ActionEvent........24, 33, 45
ActionListener ......26, 45
actionPerformed ....26, 45
Adapter .............................17
Adapter-Klassenhierarchie ...21
add...............................5, 8, 14
addActionListener .....24
addAdjustmentListener
..........................................31
addItem .............................26
addItemListener ..........27
addxxListerner ............17
AdjustmentEvent ..........31
AdjustmentListener...33
adjustmentValueChange
d .......................................33
Anordnung der Komponenten 7
Anpassungsereignis ..............31
Applet ...........................4, 37
Applets ...................................4
Appletviewer ........................38
ASCII ...................................55
AudioClip ........................46
Ausnahmen...........................51
Auswahl................................26
B
Beobachter von
Aktionsereignissen ...........25
Beobachter von
Anpassungsereignis ..........32
Beobachter von
Auswahlereignissen..........27
Beobachter von Ereignissen .20
Beobachter von
Fensterereignissen ......18, 21
Beobachter von
Textereignissen.................31
BorderLayout ...................8
BorderLayout.CENTER ..9
BorderLayout.EAST .......9
BorderLayout.NORTH.....9
BorderLayout.SOUTH.....9
BorderLayout.WEST .......9
Browsers...............................37
BufferedReader ......57, 58
BufferedWriter ............61
Button ...............................24
Byte orientiert.......................55
Canvas ...............................22
CardLayout ........................8
catch............................51, 52
Checkbox.......................7, 28
Checkboxen......................7, 28
CheckboxGroup...............28
CheckboxMenuItem........34
Choice ...........................6, 26
close..................................56
Color..................................22
Component ..........................5
Container ................4, 5, 14
Controls ............................6, 16
D
DataInput ........................64
DataInputStream ..........64
Delegation Event Mode........17
destroy .............................40
drawImage ........................47
drawLine...........................22
drawOval...........................22
drawRect...........................22
drawString ......................22
E
Ereignis.................................17
Ereignis Beobachter .............17
Ereignis Quelle .....................17
Ereignissteuerung ...........17, 18
EventObject....................17
Exeption...........................54
F
FileInputStream ...56, 58,
62
FileOutputStream..60, 62
FileReader ......................57
FileWriter ......................61
fillOval...........................22
fillRect...........................22
finaly ...............................54
first............................14, 15
FlowLayout ....................8, 9
FlowLayout.CENTER .......9
FlowLayout.LEADING.....9
FlowLayout.LEFT ............9
FlowLayout.RIGHT..........9
FlowLayout.TRAILING...9
for.......................................54
Frame....................................4
Seite 66
G
Garbage Collection...............52
getActionCommand........24
getAudioClip .................46
getCodeBase....................47
getHeight ........................38
getItem .............................26
getParameter .................42
getSize ...............................5
getSource ........................24
getText .............................29
getWidth...........................38
Graphical User Interface.........4
Graphics...............22, 38, 47
GridBagConstraints ...11
GridBagConstraints.RE
MAINDER .........................13
GridBagLayout...........8, 11
gridheight ................12, 13
GridLayout ......................10
gridwidth ..................12, 13
GUI.........................................4
H
Hierarchie der Ereignisse .....17
HTML...................................37
I
if .........................................51
Image..................................47
init ..............................39, 45
InputStream....................55
InputStreamReader ....55,
57, 58
interpretiert ...........................37
ItemEvent ........................26
ItemListener ...........27, 29
itemStateChanged..27, 29
J
Java Virtual Machine......37, 41
java.io .............................55
java.io.FileInputStre
am .....................................55
java.io.FileNotFoundE
xception.......................61
java.io.InputStream.55
java.io.OutputStream
..........................................55
JDK ........................................4
JVM......................................41
L
Label..................................29
last ..............................14, 15
Laufzeitsystem......................22
Index
Layout Manager ...........4, 7, 15
Listener.................................17
longjmp .............................51
loop ....................................46
Low-Level Ereignis..............19
Low-Level-Beobachter.........20
Quelle von Textereignissen ..31
Quellen von Ereignissen.......19
R
main ......................................5
Menu ....................................34
MenuBar .............................33
MenuItem...........................34
Menüleiste ............................33
multi-cast..............................17
Radiobuttons.........................28
read ....................................56
Reader .........................55, 57
readLine.....................57, 58
remove .................................5
rePaint ...............................5
Rollbalken ....................6, 7, 31
run.......................................48
Runnable...........................48
runtime .................................22
N
S
next ..............................14, 15
Schachtelung der Layout ......15
Schalter.............................6, 24
Scrollbar ....................7, 31
sdtout ...............................61
select ...............................26
Semantic-Level Ereignis ......19
Semantic-Level-Beobachter .20
setColor...........................22
setConstraints ............13
setFont .............................22
setjmp ...............................51
setLayout ....................6, 10
setMenuBar ......................34
setSize ...............................5
setText .............................29
setVisible ........................5
setxxListerner ............17
single-cast.............................17
sleep..................................48
Source...................................17
start............................39, 48
stdin..................................58
Steuerelementen .....................6
stop ..............................40, 46
Streams .................................55
M
O
OutputStream .................59
OutputStreamWriter..55,
61
P
paint.................. 5, 22, 38, 40
Panel....................................4
PARAM..................................42
play ....................................46
Pop-Up-Menü...................6, 26
print..................................59
println .............................59
PrintStream....................59
Q
Quelle von Aktionsereignissen
..........................................25
Quelle von Anpassungsereignis
..........................................32
Quelle von Auswahlereignissen
..........................................27
Quelle von Fensterereignissen
....................................18, 21
Seite 67
Swing......................................4
System.err ......................61
System.exit(0) ......18, 21
System.in ........................58
System.out ......................61
T
TextArea.......................7, 30
TextComponent...........7, 29
TextEvent ..................30, 31
TextField ....................7, 30
TextListener ...........30, 31
textValueChanged..30, 31
Thread ...............................48
throw............................51, 52
try.................................51, 52
Typen von Ereignissen .........19
U
Unicode ................................55
Universal Resource Locator .41
URL......................................41
W
Web-Seite .............................37
Window .................................4
WindowAdapter.........21, 26
windowClosing...18, 21, 26
WindowEvent....................18
WindowListener ............18
Writer ...............................55
WWW-Protokoll ..................41
X
xxListerner....................17
Z
zeichenorientierte ReaderKlasse ...............................57
Herunterladen