Zum Inhalt springen →

Java Kurs von 1997

Der folgende Java-Kurs ist nicht geeigenet um Java zu lernen. Ich habe ihn nur aus sentimentalen Gründen aus dem archive.org rekonstruiert und auf meine eigene Webseite kopiert. Ich habe nicht geprüft, ob auch nur irgendetwas aus dem Kurs heute noch funktioniert. Also bitte mit Vorsicht genießen.

Grundlagen

Dieser Teil ist für diejenigen besimmt , die bisher noch nie mit dem JDK (Java Development Kit) gearbeitet haben, hier beschreibe ich eine Ausschnitt aus dem Leistungsumfang, und einige Hilfen zur Installation unter Win95. Die eigentlichen „Grundlagen“ zur Programmierung werde ich in den Jeweiligen Lektionen behandeln.

Das wichtigste mal als erstes:

Das JDK wird von der Firma Sun zu privaten Zwecken kostenlos zur Verfügung gestellt. Momentan liegt es in der Version 1.1.1 als Beta zum Downloaden auf der Sun Homepage bereit.

Es ist für folgende Betriebssysteme erhältlich:

Solaris (Wer hat daran auch nur gezweifelt 🙂 )Win95/NTMacOsLinux (nur Version 1.0.2, nicht auf der Homepage bei Sun )

Die im JDK mitgelieferten Tools sind:

javah(Einbindung von C code)javac(Der Java „Compiler“)java(Der Bytecode Interpreter für Applikationen)appletviewer(Der Bytecode Interpreter für Applets)jdbUnd „last but not least“ der Debugger)

Natürlich beinhaltet das JDK noch einige andere Werkzeuge, die hier aber vorerst nicht weiter Interessieren!! 🙂
In den im folgenden dargebotenen Lektionen werden wir mit 2 (evtl. 3) dieser Tools arbeiten. Dies werden sein :
javac, java (und wenn ich mich selbst etwas damit eingearbeitet habe auch der jdb).

Der Java Compiler javac

hat folgende Optionen:-classpath[path]Hiermit ändert man das Verzeichnis, indem nach Klassen gesucht wird.-nowarnKeine Ausgabe von Warnungen (beim JDK 1.1 sehr zu empfehlen)-oOptimierung des Bytecodes. Der Bytecode wird zwar etwas größer, aber die Ausführung schneller-d[path]Die Klassendatei wird hiermit in einem anderen Verzeichniss abgespeichert-gWird angegeben, wenn man den Bytecode noch debuggen möchte

Der Java Interpreter java

hat folgende Optionen:-debugErlaubt es den jdb sich an das jeweilige Javaprogramm anzuheften-classpath[path]Zur Angabe des Pfades, in dem nach Klassen gesucht werden soll-v, -verboseBei jedem laden einer Klasse wird eine Nachricht auf die Standardausgabe geschrieben

Eine vollständige Liste der Optionen ist in der JDK Dokumentation enthalten.

Die Installation

Die installation des JDK ist denkbar einfach. Einfach die Zip Datei in das gewünschte Verzeichniss kopieren, und entpacken. Die Verzeichnisse werden automatisch erstellt und alle Dateien an der richtigen Stelle untergebracht.
Die neuste Version wird auch schon mit einem Installationsprogramm zur Verfügung gestellt. Einfach nur ausführen und 1-2 mal OK oder so drücken.
Jetzt nur noch PATH Variable aktualisieren und fertig.

Verzeichnisstruktur des installierten JDK

Hier PATH=%PATH%;C:\JAVA\BIN

[JAVA]-<>-[BIN]
       |
       <>-[DEMO]-<>-[ANIMATOR]-<>-[AUDIO]
       |    	 |             |
       |         |	       <>-[IMAGES]
       |         |
       |         <>-[CLOCK]
       |         |
       |         <>-[...
       |
       <>-[INCLUDE]
       |
       <>-[LIB]---[SECURITY]

Alle MAC Besitzer mögen mir jetzt verzeihen, ich hab nämlich keine Ahnung ob es da synonym abläuft. Falls nicht bin ich für jede Anregung in dieser Hinsicht überaus dankbar.

Ich hoffe ich hab hier nichts wichtiges vergessen. Falls jemandem etwas auf- oder einfällt schreib mir doch einfach eine Mail.
PS.: Bitte keine Mails über meine Rechtschreibung, nur weil ich euch teilweise schon um 2 Rechtschreibreformen voraus bin.


F A Q

Weitere Java FAQ’s

1.Allgemeines (E)2.Allgemeines (E)3.Java und Netz (E)4.Java FAQ Archiv (E)5.ACME Java FAQ (E)6.Read about Java (E)de.comp.lang.java (D)

Die Eigentlichen Frequently Asked Questions werden sich hier im laufe der Zeit nach und nach entwickeln. So Gott will :-)).


Lektion 1

In der ersten Lektion werde ich jeden Schritt, von der Eingabe des Quellcodes, bis zur Ausführung des Programmes, beschreiben. Damit jeder damit zurechtkommt, auch wenn er praktisch noch keine Grundkenntnisse hat. Das erste Programm ist natürlich auch hier nur ein weiteres langweiliges HelloWorld Progrämmchen.
An diesem Beispiel kann man praktisch nichts lernen, außer wie man mit dem JDK arbeitet.

import java.io.*;                                      //Inpotieren der Java Ein/Ausgabe Klasse
public class HelloWorld {                              //Klassen und Programmname
        public static void main (String argv[]) {      //Mainfunktion wird beim Start ausgeführt
                System.out.println ("Hello World ");   //Ausgabe des Strings auf die Standard Ausgabe
        }
}

Als erstes braucht man den Sourcecode. Der wird einfach in einen Editor eingegeben (sogar Abschreiben ist hier erlaubt 🙂) oder noch einfacher direkt kopiert. Jetzt wird er unter dem Namen HelloWorld.java abgespeichert. !! Aber Achtung Groß- und Kleinschreibung beachten und beim Editor von diesem komischen W!n95 ist es mir nicht gelungen die Extention .java einzugeben. Stattdessen bekam ich HelloWorld.java.txt oder so.!! Als nächstes benötigt man natürlich ein Arbeitsverzeichnis, in dem man den Sourcecode speichert. Ich persönlich habe die Sourcecodes im Verzechnis „Seminar\Lektion1“. Aber das bleibt jedem selbst überlassen, wie er seine Festplatte organisiert. Wenn das Programm im Verzeichniss abgelegt ist und es den RICHTIGEN Namen hat öffnet man ein Dos Fenster, ein Terminal oder was man bei den jeweiligen Betriebssystem so benuzt um einfache Befehle direkt eingeben zu können.
Jetzt (wenn bis hier alles geklappt hat) kann man an das Übersetzen gehen. Einfach in das Verzeichnis des Programmes wechseln und mit

javac HelloWorld.java

einen Bytecode erzeugen. Einige von Euch werden Warnings ertragen müssen, die von der Version des JDK abhängig sind. Falls keine unerwarteten Fehler aufgeteten sind sollte sich jetzt eine neue Datei mit dem Namen HelloWorld.class im Verzeichnis befinden. Einmal tief Luft holen…. und

java HelloWorld

eingeben. Das war für heute erst mal alles. Wer jetzt noch nicht genug hat kann auch noch eine Übungsaufgabe mit auf den Weg bekommen.
Ich schlge vor den 2.ten Teil am 9.5.97 in Angriff zu nehmen und bis dahin mit der Gewissheit zu Leben ein Java Programmierer zu sein 🙂.


Übung 1

Die erste Übung besteht darin, am HelloWorld Programm etwas herumzuspielen und einfach mal auszuprobieren, was passiert, wenn …..

Eine weitere etwas schwierige Übung ist es ein Programm zu schreiben, daß es nach einer Ausgebe z.B. „Wie ist Dein Name“ auf eine Eingabe wartet, und dann den String „Hallo [NAME] !“ ausgibt.
Hierzu sind einige winzige Kenntnisse notwendig.🙂
1. Die Methode readLine ()2. Die Klasse DataInputStream ([InputStream])3. System.in –> ist ein InputStream4. Die IOException, Try und Catch
Hierzu gebe ich noch das Grundgerüst des Programmes an. Es ist einfach nur um die Eingabe zu ergänzen.

import java.io.*;
public class InOut {	
	static String Name;				//Die Klasse Name vom Type String
	public static void main (String argv[]) {
		System.out.println ("Wie ist Dein Name");
		...
		...
		...
		...
		...
		...
		System.out.println ("Hallo "+Name+" !");
	}
}

Viel Spaß damit und lass Dich nicht entmutigen. Lies einfach in der API des JDK nach. Was Du brauchst kannst Du der Liste entnehmen.


Lösung zu Lektion 1

import java.io.*;

public class InOut { 
	public static void main (String argv[]) {
		String Text = new String;
			//Speicher reservieren für einen String
		System.out.println ("Bitte Deinen Namen eingeben");
		try {	
			DataInputStream in = new DataInputStream (System.in);
			Text = in.readLine();
			// Einlesen eines Strings mit einer völlig veralteten Methode
		} catch (IOException e) { 
			System.out.println ("Fehler bei der Eingabe von Text1");
			// Wenn eine IOException auftritt wird der rest des 
			// try Blockes übersprungen
		}
		System.out.println ("Hallo "+Text);
			// Ausgabe auf die Standardausgabe
	}
}

Dies ist die simpelste Form der Ein/Ausgabe. Keine Fenster und nichts.

Lektion 2

Nachdem die erste Lektion geschafft währe, wird es dieses mal etwas anspruchsvoller, falls Du noch keine Programmiersprache kannst wirst Du in dieser Lektion mit gewissen Problemen konfrotiert. Die nach dieser Lektion hoffentlich alle beiseite geräumt worden sind. Diese Lektion wird sich mit den Datentypen und mit einfachen Strukturen befassen.
Diese Lektion ist sehr wichtig, da es ohne ein gewisses Verständnis der grundlegenden Programmiertechniken einfach nicht möglich ist selbstständig zu programmieren.
Und die Moral von der Geschichte?!!?!?!?? Bloß nicht aufgeben !!!

1. atomare Datentypen

TyplängeBereich
boolean8true/false
byte8-128 bis +127
char1665535 unterschiedliche Zeichen
short16-32768 bis 32767
int32-2147483648 bis 2147483647
float3210^-38 bis 10^38 ca. 8 Stellen
long64-9223372036854775808 bis 9223372036854775807
double6410^-308 bis 10^308 ca. 16 Stellen

Alle anderen Datentypen basieren auf einer oder mehrerer dieser Typen. Die Klasse String basiert z.B. auf einer Liste von char Typen, und stellt noch eine Reihe von sehr nützlichen Methoden zur Verfügung.

2. Konstanten

Innerhalb einer Klasse kann man Konstanten deklarieren. Solche Konstanten können von jedem gültigen Typ sein. Das Schlüsselwort für Konstanten ist final.
Ein paar Beispiele:

public class Test { 
	static	final 	String	NAME		= "All Bundy";
	final 		boolean	VERHEIRATET	= true;
	final 		int	KINDER		= 2;
	final		String	JOB		= "Schuhverkäufer";
	public static void main (String args[]) {
		final	byte	IQ		= (byte)JOB.length(); // = 14
		System.out.println (IQ);
	}
}

3. Arrays

Ein Array ist eine Liste von Variablen, die alle vom gleichen Typ sind. Solche Listen können in mehrere Dimensionen unterteilt werden und sind in ihrer Größe nur durch den Speicher begrezt. Es ist allerdinds nicht unbedingt sinnvoll so verdammt große Datenmengen zu verwalten, da hierdurch das ganze System gebremst wird und andere Anwendungen sich evtl. wundern, daß der ganze Arbeitsspeicher verschwunden ist.
Teste einfach mal das folgende kleine Programm, das die einfache Aufgabe hat sich 4 (für int) * 50000 * 10 Byte Speicher zu reservieren, und ihn sofort wieder frei zu geben.

public class Test {
	public static void main (String argv[]) {
		int x[][];
		x = new int [50000][10];
	}
}

Um das Freigeben des Speichers muß man sich nicht kümmern. Java ist so schlau den Speicher selbst wieder zu „befreien“. Dies übernimmt der sog. Garbage Collector, der während der Laufzeit ermittelt, welche Objekte nich mehr benötigt werden.

4. Die Klasse String

Java ist eine seeehr objektorientierte Programmiersprache. Das sieht man daran, das z.B. String oder auch Integer Klassen sind. Ihnen können nicht nur Werte zugeweisen werden. In der Dokumentation des JDK 1.1 sind 11 Konstruktoren und 46 Methoden beschrieben, die alle nur zur Klasse String gehören.
Ein kleines Beispiel zu String:

import java.io.*;

public class Test { 
	public static void main (String argv[]) {
		String Text1;
		String Text2;
		String Text3;
		Text1 = new String ();	
			// Konstruktor 1: ein leerer String
		Text2 = new String ("Sein oder nicht sein bla bla bla");
			// Konstruktor 2: mit einer Zeichenkette initialisiert 
		Text3 = new String (Text2.substring (21));
			// Konstruktor 3: mit einem String initialisiert
		try {	
			DataInputStream in = new DataInputStream (System.in);
			System.out.println ("Eingabe :");
			Text1 = in.readLine();
			// Einlesen eines Strings mit einer völlig veralteten Methode
			
		} catch (IOException e) { 
			System.out.println ("Fehler bei der Eingabe von Text1");
		}
		System.out.println (Text1);
		System.out.println (Text2);
		System.out.println (Test3);
			// Ausgabe auf die Standardausgabe
	}
}

Falls Du schon mit der Version 1.1 oder höher arbeitest, erscheint beim compilieren die Fehlermeldung:

Test.java:17: Note: The method java.lang.String readLine() in class java.io.DataInputStream has been deprecated. Please consult the documentation for a better alternative.

Das ist nicht schön, aber nicht jeder hat die Möglichkeit mit der Version 1.1 zu arbeiten. Für Linux ist beispielsweise nur die Version 1.0.2 verfügbar, daher werde ich auch in Zukunft versuchen zu dieser Version „kompatibel“ zu bleiben. Wenn es Dich stört, sieh es einfach als Bonusaufgabe an einen Sourcecode zu erzeugen der Deiner Java Version entspricht.

5. Datentypumwandlung

Die Parameterübergabe an das Programm erfolgt vollständig zeichenorientiert. Was aber wenn das Programm als Parameter eine Zahl benötigt? Ganz einfach man wandelt den String in eine Zahl.
Das folgende Beispiel demonstriert dies an einem einfachen Additionsprogramm.

public class Test { 
	public static void main (String args[]) {
		int Summe=0;
		String Ausgabe = new String();
		if (args.length == 0) {
			System.out.println ("Fehler: Aufruf z.B. java Test 1 2 3 4 5 ");
			return;
		}
		for (int i = 0;i < args.length;i++) {
			Integer Summand = new Integer (args[i]);
				//Typkonvertierung von String nach Integer
			Summe = Summe + Summand.intValue();
		}	
		Ausgabe = Ausgabe.valueOf (Summe);
				//Typkonvertierung von Integer nach String
		System.out.println ("Ausgabe als String");
		System.out.println (Ausgabe);
		System.out.println ("Ausgabe des int Wertes");
		System.out.println (Summe+"");
				//Eine einfache Alternative 
	}
}

6. Kontrollstrukturen

Java besitzt die gleichen Kontrollstrukturen wie sie von C her bekannt sind. Wer also schon mit C, C++ oder einer vergleichbaren Sprache gearbeitet hat kann diesen Teil getrost überspringen.

1.if (boolean) { //Befehlsblock } else { //Befehlsblock } Bedingte Verzweigung
2.while (boolean) { //Befehlsblock } Abweisende Schleife
3.do { //Befehlsblock } while (boolean); Nicht abweisende Schleife
4.for (init;boolean;Schrittweite) { //Befehlsblock } Zählschleife
5.switch (Ausdruck) { case const1: //Befehlsblock break; case const2: //Befehlsblock break; . . . default: //Befehlsblock break; } Mehrfachauswahl

Alle Kontrollstrukturen haben eines gemeinsam. Sie werden alle durch einen boolschen Ausdruck gesteuert*. Er kann die Zustände true und false haben und wird entweder vorher oder direkt in den Klammern erzeugt (siehe Bsp. zu 5). Man benuzt hierfür entweder Vergleichsoperatoren, logische Operatoren oder ruft eine Methode auf, die eine boolean Wert als Rückgabewert besitzt.
* Auch die Mehrfachauswahl wird so gesteuert. Der boolsche Wert wird durch einen Vergeich zwischen dem Ausdruck und der jeweiligen Konstante erzeugt (gleich -> true / ungleich -> false ).

a< ba kleiner b
a>ba größer b
a<=ba kleiner oder gleich b
a>=ba größer oder gleich b
a==ba gleich b
a!=ba ungleich b
a&&b;a Und b (für boolsche Ausdrücke)
a||ba Oder b (für boolsche Ausdrücke)
a&b;a Und b (Bittweise)
a|ba Oder b (Bittweise)
a^ba exkusiv Oder b (Bittweise)

Einige Beispiele zum Verständnis:

1) Ermitteln der größten Zahl

public class Test {
	public static void main (String argv[]) {
		int x=10;
		int y=20;
		int z=15;
		if (x>y) {
			if (x>z) {
				System.out.println ("Max = "+x);
			} else {
				System.out.println ("Max = "+z);
			}
		} else {
			if (y>z) {
				System.out.println ("Max = "+y);
			} else {
				System.out.println ("Max = "+z);
			}
		}
	}
}

2) Einen String zerschneiden

public class Test {
	public static void main (String argv[]) {
		String Text = new String ("Ich bin ein String");
		int x=0;
		while (Text.length() != 0) {
			x++; // Increment x=x+1
			System.out.println (Text);
			Text = Text.substring (0,Text.length()-1); 
			//erstes Zeichen abschneiden
		}
		System.out.println (x+" Zeichen hatte der Text");
	}
}

3) Texteingabe mit einer nicht abweisenden Schleife. Abbruch mit Stop

import java.io.*;
public class Test {
	public static void main (String argv[]) {
		String Text[] = new String [10]
		DataInputStream in = new DataInputStream (System.in);
		int count=0;
		do { 
			try {
				Text[count]=in.readline ();
			} catch (IOException e) {}
			count++;
		} while (Text[count-1].compareTo ("Stop")!=0 && count != 9);
		for (int i=0;i< count;i++) {
			System.out.println (Text[i]);
		}
	}
}

4) Ein einfaches Menü

import java.io.*;

public class Test {
	public static void main (String argv[]) {
		String Text = null;
		System.out.println ("1................xxxxxxxxxx");
		System.out.println ("2..................xxxxxxxx");
		System.out.println ("3................xxxxxxxxxx");
		System.out.println ("4.....................xxxxx");
		DataInputStream in = new DataInputStream (System.in);
		try {
			Text=in.readLine();
		} catch (IOException e) {}
		char x = Text.charAt(0);
		switch (x) {
			case '1':
				System.out.println ("Sie haben 1 ausgewählt");
				break;
			case '2':
				System.out.println ("Sie haben 2 ausgewählt");
				break;
			case '3':
				System.out.println ("Sie haben 3 ausgewählt");
				break;
			case '4':
				System.out.println ("Sie haben 4 ausgewählt");
				break;
			default :
				System.out.println ("Auswahl "+x+" ist falsch");
		}
	}
}

7. Funkltionen

Funktionen oder Methoden hast Du jetzt schon öfters benutzt. Die main Funktion ist die wichtigste in einer Applikation, und von ihr geht alles aus. Um eine solche Funktion möglichst übersichtlich zu halten ruft man von hier aus andere Funktionen auf, die vieleicht wieder andere Funktionen aufruft usw. So kann man auch große Programme noch überblicken. Man kann eine Funktion als void deklarieren, was bedeutet, daß sie keinen Wert als Rückgabe an die aufrufende Funktion besitzt (siehe main). Es ist aber auch möglich, einer Funktion als Rückgabewert einen beliebigen Datentyp oder sogar eine Klasse zuzuweisen. Die Methode readLine hat als Rückgabewert z.B. einen String.
Deklaration einer einfachen Funktion die das Quadrat eines Wertes errechnet und dann das Ergebnis an die aufrufende Funktion zurück gibt.

static void xyz (int Eingabe) {
	int Returnwert;			// Lokale Variable Returnwert
	Returnwert = Eingabe*Eingabe; 	// Quadrat der Variable Eingabe
	return (Rückgabe);
}

In einer Funktion kann man lokale Variablen deklarieren, die nur gültigkeit haben, während die Funktion ausgeführt wird. Falls es vorkommt, daß eine lokale Variable den selben Variablennamen benutzt, wie eine globale (allgemein gültige) Variable kann man mit Hilfe von this die glogale Variable ansprechen.
Der Klassenbezeichner this spezifiziert immer die aktuelle Klasse.

z.B. this.Name = "Michael"; 	// globale Variable 
     Name = "Michael";		// lokale Variable falls in der Funktion lokal deklariert

Im Funktionskopf spezifiziert man ob eine Funktion von außerhalb der Klasse aus aufgerufen werden kann oder ob die Funktion nur innerhalb der Klasse aufgerufen werden darf. Diese Spezifikation als public ist optional und wird an den Anfang des Funktionskopfes geheftet (siehe oben in main). Auch optional ist die angabe static. Sie bewirkt, daß die Funktion nicht im Speicher verschoben werden darf. Die globalen Variablen die von einer static Funktion aus benutzt werden, müssen auch als static deklariert werden.
Als nächstes wird der Typ der Funktion angegeben, der den Rückganbewert festlegt und der Funktionsname der den anderen Funktionen hilft sie zu finden :-)).

[öffenlichkeitsschlüssel] [static]  Returntyp Name ([Typ] [Varname];[Typ] [Var... ) {
	// Anweisungen
[return [(ReturnVariable)]]
}

So, daß kannst Du Dir jetzt erst einmal in Ruhe auf der Zunge zergehen lassen.
..







In der Lektion 3, die ab dem 16.5.97 verfügbar ist, werden Funktionen und Klassen im Vordergrund stehen, und es wird ein erstes Fenster erzeugt. Aber bis es so weit ist erst mal noch eine Aufgabe.

8. Übungsaufgaben

Berechnung der Fakultät einer beliebigen positiven ganzen Zahl bis 10.1. Iterativ (in einer Schleife)
Die Fakultät einer Zahl berechnet sich folgendermaßen: Man zählt von 1 an hoch und multipliziert den Zähler mit dem vorherigen Ergebnis bis der Zähler gleichgroß ist, wie die Zahl für die die Fakultät berechnet werden soll.
z.B. 7 -> 1*2*3*4*5*6*7 = 5040
Achtung: die Fakultät von 0 ist 1 und muß somit gesondert behandelt werden !!
2. Rekursiv (mit einer Funktion, die sich selbst mit veränderten Parabetern wieder aufruft bis das Ergebnis feststeht)
z.B. eine Funktion „RekFakultät (int last,count,fak)“ die mit den Werten 1,1,Wert aufgerufen wird, last und count multipliziert, cout um 1 erhöht und sich selbst mit den neuen Werten aufruft.Nach der Multiplikation muß noch abgefragt werden, ob count schon so Groß ist wie Wert. Falls das der Fall ist gibt man des Ergebnis mit return (xxx) zurück


Lektion 3

Hallo!
In der dritten (etwas verspäteten) Lektion geht es um Klassen und Funktionen. Du hast ja vielleicht schon die letzte Aufgabe (Fakultät berechnen) gelöst. Hier solltest Du eine Funktion schreiben, die dieses Problem auf recht einfache Art und Weise löst.
In dieser Lektion werde ich das Programm aufgreifen und eine grafische Oberfläche ergänzen. Man kann das Problem nun auf mehreren Wegen lösen. Jeder hat halt so seinen Programmierstil, ich werde die Anwendung in 2 Klassen zu unterteilen. Natürlich ist es kein Problem ein so kleines Programm in einer einzigen Klasse zu programmieren und auch nachträglich noch zu bearbeiten, aber wenn die Programme dann doch mal größer werden wünscht man sich man hätte nicht alles in einer Klasse oder sogar nur eine Funktion wenn dann doch mal eine Änderung vorgenommen werden muß.
So, jetzt aber zum wesentlichen:

  • 1.Klasse MyWindow
    Wie der Name es schon vermuten läßt, ist die Klasse für das Fenster verantwortlich.
  • 2.Klasse Fakultät
    Hier wird die Fakultät berechnet. ( das ä ist übrigens kein Fehler. Java akzeptiert auch solche Sonderzeichen)

Da die Klasse MyWindow ein Fenster mit allem drum und dran sein soll, wird sie von der Klasse Frame abgeleitet. Das sieht dann so aus.

import java.awt.*; 	// in diesem Paket ist die Klasse Frame drin

class MyWindow extends Frame {
	// Klasse MyWindow erbt alle Funktionen der Klasse Frame 
	public static void main (String argv[]) {
		MyWindow MyTestFrame = new MyWindow ();
		// Aufrufen des Konstruktors, den die Klasse von Frame geerbt hat
		MyTestFrame.resize (200,200);
		// Größe festlegen
		MyTestFrame.show ();
		// Fenster anzeigen
	}
}

Diese Klasse ist so ausführbar, kann aber nicht mehr beendet werden. Außer mit Hilfe des Taskmanagers von Windows oder einem Kill unter UNIX. Für den MAC kann ich hier auch wieder nicht weiterhelfen ?!??!?!!?!!?!
Um das Fenster wieder zu entfernen muß man die Funktion System.exit (int) benutzen. die dann ausgeführt wird, wenn die Klasse ein WINDOW_DESTROY Event erhält. Und das geht so:

import java.awt.*;

public class MyWindow extends Frame {
	public static void main (String argv[]) {
		MyWindow MyTestFrame = new MyWindow ();
		MyTestFrame.resize (200,200);
		MyTestFrame.show ();
	}

	public MyWindow () {
			// Konstruktor 
		super ("Mein erstes Fenster");
	}

	public boolean handleEvent (Event e) {
		switch (e.id) {
			case Event.WINDOW_DESTROY:
				// Anwendung beenden Message
				dispose ();
					// Freigeben der Ressourcen
				System.exit (0);
		}
		return (true);
	}
}

Die Funktion handleEvent erhält Messages die an das Fenster gerichtet sind. In der switch case Auswahl kann man dann jede Meldung gezielt auswerten und daraufhin einen Anweisungsblock ausführen.
Der 2.te Schritt ist nun das Design der Oberfläche. Man kann auch hier wieder seinen eigenen Stil in das Programm einbringen. Jeder hat halt so seine Vorlieben ( Menüs,Buttons,Dialoge…). Java bietet all diese Möglichkeiten in vorgefertigten Objekten, die nur initialisiert und auf die Oberfläche gebracht werden müssen. Ich werde 2 Button, ein Choice und ein TextField benutzen. Dies ist zwar eine sehr unschöne Arbeitsoberfläche, aber Du kannst sie ja durch ein paar Labels noch verbessern.
Im Quellcode sieht das dann so aus.

import java.awt.*;

public class MyWindow extends Frame {

	TextField Fakultät;
	Button Rechne;
	Button Exit;
	Choice Eingabe;
	int count;

	public static void main (String argv[]) {
		MyWindow MyTestFrame = new MyWindow ();
		MyTestFrame.resize (200,100);
		MyTestFrame.show ();
	}

	public MyWindow () {
			// Konstruktor 
		super ("Fakultät");
		setLayout (new GridLayout (2,2));
			// Layouttyp festlegen
		Fakultät = new TextField (10);
		Rechne = new Button ("Berechnung");
		Exit = new Button ("Exit");
		Eingabe = new Choice ();
		for (int i=0;i<=10;i++)
			Eingabe.addItem (""+i);
			// 0-10 in Choice
		add (Fakultät);
		add (Rechne);
		add (Eingabe);
		add (Exit);
	}

	public boolean action (Event e,Object o) {
		if (e.target instanceof Button ) {
			Fakultät.setText ("Button");	
			if ("Berechnung".equals(o)) {
				Fakultät.setText ("Hallo");	
			}
			if ("Exit".equals(o)) {
				dispose ();
					// Freigeben der Ressourcen
				System.exit (0);
					// Programm beenden
			}
		}
		return true;
	}
}

Im Konstruktor wird erst mal ein Layouttyp festgelegt. Mit den Layouttypen wird sich aber eine andere Lektion befassen, deshalb möchte ich hier nur dazu auffordern, etwas damit zu experimentieren. Es gibt noch eine unerschöpfliche Menge an Möglichkeiten. In diesem Programm wird einfach nur ein Layout festgelegt, welches das Fenster in ein 2×2 Raster aufgeteilt. Jetzt können von oben links nach unten rechts die Objekte mit add eingefügt werden.

Das war’s zur Oberfläche, nun kommen wir zur eigentlichen Anwendung. Die Klasse Fakultät.
Als erstes mal der komplett lauffähige Quellcode, den ich weiter unten noch erkläre.

File 1: (MyWindow.java)

import java.awt.*;

public class MyWindow extends Frame {

	TextField FakultätWert;
	Button Rechne;
	Button Exit;
	Choice Eingabe;
	int count;

	public static void main (String argv[]) {
		MyWindow MyTestFrame = new MyWindow ();
		MyTestFrame.resize (200,100);
			// Größe festlegen
		MyTestFrame.show ();
			// Fenster anzeigen
	}

	public MyWindow () {
			// Konstruktor 
		super ("Fakultät");
		setLayout (new GridLayout (2,2));
			// Layouttyp festlegen
		FakultätWert = new TextField (10);
		Rechne = new Button ("Berechnung");
		Exit = new Button ("Exit");
		Eingabe = new Choice ();
		for (int i=0;i<=10;i++)
			Eingabe.addItem (""+i);
			// Komponenten auf dem Bildschirm plazieren
		add (FakultätWert);
		add (Rechne);
		add (Eingabe);
		add (Exit);
	}

	public boolean action (Event e,Object o) {
		if (e.target instanceof Button ) {	
			if ("Berechnung".equals(o)) {
				Fakultat MyFakultat = new Fakultat();
					// Klasse Fakult(a)t initialisieren
				Integer AktEintrag = new Integer (Eingabe.getSelectedItem());
				int Eintrag = AktEintrag.intValue();
					// Wert des Eintrags ermitteln
				int FakWert = MyFakultat.getFakultät (Eintrag);
					// Fakultät berechnen
				FakultätWert.setText (FakWert+"");	
					// Ausgabe im TextField
			}
			if ("Exit".equals(o)) {
				dispose ();
					// Freigeben der Ressourcen
				System.exit (0);
					// Programm beenden
			}
		}
		return true;
	}
}

File 2: (Fakultat.java) Fakultat deshalb, weil es bei Fakult(ä)t Probleme mit dem Filesystem geben kann

public class Fakultat {	
	public int getFakultät (int Eingabe) {
		if (Eingabe == 0) {
			return 1;
		} else {
			//return (getFakultätSchleife (Eingabe));
			// Rekursiv und in einer Schleife
			// Können beide mal probiert werden
			return (getFakultätRekursiv (Eingabe,1));
		}
	};
	int getFakultätSchleife (int Wert) {
		int FakultätErgebnis=1;
		for (int i=1;i<=Wert;i++) {
			FakultätErgebnis = FakultätErgebnis*i;
		}
		return (FakultätErgebnis);
	}

	int getFakultätRekursiv (int Wert,int Count) {
		if (Wert>Count) {
			// ruft sich selbst so lange auf, bis Count = Wert ist
			Wert = getFakultätRekursiv (Wert,Count+1);
			return (Wert* Count);
		} 
		return (Wert);
	}
}

Compilieren und dann java MyWindow ausführen, da sie die main Funktion hat.

Die Klasse MyWindow hat keine Methode handleEvent mehr. Statt dessen ist jetzt die Methode action für die Behandlung der Events verantwortlich. Sie kennt nur die Events „Berechnung“ und „Exit“, für die 2 Button. Der interessante Button ist der „Berechnung“ Button. Hier wird erst der Wert ermittelt, für den die Fakultät berechnet werden soll. Die Klasse Fakult(a)t wird initialisiert und die Methode getFakultät aufgerufen. Die öffentliche Methode getFakultät ruft wiederum eine interne Methode auf, die dann die Fakultät entweder rekursiv oder in einer Schleife berechnet, und den errechneten Wert als Rückgabe hat.
Wenn man bedenkt, das der Kern des Programmes (die Methoden zum berechnen der Fakultät) nur wenige Zeilen lang ist, dann ist das Drumherum doch schon verhältnismäßig groß. Im Verhältnis zu einigen anderen Hochsprachen ist das Programm aber noch innerhalb eines vertretbaren Rahmens und somit ein „Konkurrenzfähiges“ Produkt auf dem Markt der Fakultät berechnenden Programme. ;-))

Bis jetzt hat sich diese Lektion nur mit den Klassen, die als public deklariert sind, beschäftigt. Es gibt aber auch noch die Möglichkeiten eine Klasse oder Methode als protected oder als private protected zu deklarieren, was dann folgende Bedeutung hat:

  • 1.private
    Eine als private erklärte Methode ist nur innerhalb der Klasse sichtbar, wird nicht vererbt und kann nicht überschrieben werden.(Gegenteil von public)
  • 2.protected
    Hier verhält es sich fast genauso wie bei der private Deklaration, nur sind die Methoden aus anderen Klassen des gleichen Packages und von Nachfahren (auch aus anderen Paketen) der Klasse sichtbar.
  • 3.private protected
    Hier verhält es sich so, daß so deklarierte Methoden nur innerhalb der Klasse und von Nachfahren der Klasse benutzt werden dürfen.( entspricht protected in C++)
  • 4.public
    Public ermöglicht einen uneingeschränkten Zugriff auf das entsprechende Element.
  • 5.final (Klasse)
    Kann nicht überschrieben werden und abgeleitete Klassen dürfen nicht final sein.
  • 6.syncronisizeable (Klasse)
    Nur für Multithreading-Programme von Bedeutung
ClassModifiers class className [extends Elternklasse] [implements interfaces] {
	// Inhalt der Klasse 
}

Das soll hierzu erst einmal reichen, falls es in einer folgenden Lektion noch benötigt wird werde ich noch näher darauf eingehen. Wie Klassen initialisiert werden kann man im obigen Beispiel zur Berechnung der Fakultät sehen. Dort wird aus der Klasse MyWindow heraus die Klasse Fakult(a)t mit dem Namen MyFakultät initialisiert. Jetzt da ein Objekt der Klasse erzeugt wurde, ist jedes Element, welches als public deklariert ist von der Klasse MyWindow aus erreichbar. So kann dann auch die öffentliche Methode getFakultät (..) ausgeführt werden.

Objektname.Methodenname (Parameterliste); 

Eine Klasse ohne Methoden hat nur sehr selten einen Sinn. Um also in einer Klasse richtig nutzen zu können, benötigt man Methoden, die folgendermaßen deklariert werden:

MethodModifiers ReturnWert MethodenName (Argumentenliste) {
	// Inhalt der Methode
	return (ReturnWert) // außer bei void
}

In der Klasse Fakult(a)t sind die Methoden

deklariert.

Zum Schluß möchte ich mich noch einmal dafür entschuldigen, daß es eine kleine Verspätung gegeben hat. Hierdurch gibt es dann natürlich auch eine kleine Verschiebung im Zeitplan, der nächste Termin ist dann der 28.5.97.

PS.: In den deutschen Newsgroups habe ich gelesen, daß das JDK1.1.1 für Linux endlich verfügbar ist. Was bedeutet, daß ich versuchen werde, mich ab der nächsten Lektion ausschließlich auf diese Version zu beziehen.

So, jetzt aber zur

Übung

Die Übung zu der Lektion ist es, ein Programm zu schreiben, welches die aktuelle Uhrzeit ermittelt. Diese Uhrzeit kann dann in einem TextField ungefähr so [Std:Min:Sec] angezeigt werden. Die Oberfläche und das ermitteln und umwandeln der Uhrzeit sollen wie oben in 2 unterschiedliche Klassen integriert werden. Als Hilfe kann man sich mal das Demoprogramm Clock und die Doku zum Package util ansehen. Clock ist im JDK enthalten. Es ist zwar ein Applet, aber ….. Die Methode getTime ist eine der wenigen, noch nicht veralteten Methoden der Klasse Date, die zur Berechnung der Uhrzeit benutzt werden kann. Die Berechnung der Uhrzeit aus dem Rückgabewert ist zwar nicht ganz einfach, aber probieren geht bekanntlich über studieren.


Lektion 4

Layoutmanager allgemein

In der letzten Lektion haben wir schon einen Layoutmanager benutzt. Ganz allgemein ist das Layout ein Container, den man nach und nach mit add (..) füllt. Der Layoutmanager hat dabei die Aufgabe der Verwaltung aller ankommenden Komponenten.
Hier gibt es dann mehrere Manager, die jeweils auch noch mit Hilfe von eigenen Methoden konfiguriert werden können. Zusätzlich kann man auch Layouts ineinander verschachteln, womit dann wohl keine Wünsche mehr offen bleiben dürften.
Der flexibelste Layoutmanager ist der Gridbaglayoutmanager, der hier nur einmal gezeigt wird, da er sehr umfangreich und für den Einsteiger eher ungeeignet ist.

FlowLayout

Das Flowlayout ist das einfachste Layout von allen, es positioniert die Komponenten von links nach rechts und wenn die Zeile voll ist beginnt es eine Zeile tiefer, fängt wieder von links an und geht Komponente für Komponente weiter nach rechts usw.

Beispiel

import java.awt.*;

public class FlowTest extends Frame {
	public static void main (String argv[]) {
	FlowTest TestFrame = new FlowTest ();
                TestFrame.resize (600,400);
                // Größe festlegen
                TestFrame.show ();
                // Fenster anzeigen
	}
	
	public FlowTest () {
                        // Konstruktor
                super ("Testen des Flow Layouts");
		setLayout (new FlowLayout ()); 
		for (int i=1;i<=100;i++)
                	add (new Button ("Test"+i));
        }

}

Dieses Beispiel hat die Größe 600×400 Pixel. Wenn man jetzt die Größe ändert kann man gut sehen, wie das Layout der Applikation an die Größe des Fensters angepaßt wird.
Zusätzlich gibt es noch eine Menge Methoden zum einstellen des Layoutmanagers. z.B. kann man den horizontalen und vertikalen Abstand zwischen den Komponenten festlegen oder die gesetzten Werte abfragen.

BorderLayout

Wie der Name schon vermuten läßt kann man die Komponenten am Rand plazieren. Diesen Layoutmanager habe ich noch nie benutzt, aber er ist sicher sehr Hilfreich in Anwendungen, wo etwas in verschiedene Richtungen gedreht werden soll oder beim Scrollen auf einer Landkarte und so.

Beispiel

import java.awt.*;


public class BorderTest extends Frame {
	public static void main (String argv[]) {
	BorderTest TestFrame = new BorderTest ();
                TestFrame.resize (200,200);
                // Größe festlegen
                TestFrame.show ();
                // Fenster anzeigen
	}
	
	public BorderTest () {
                        // Konstruktor
                super ("Testen des Border Layouts"); 
		setLayout (new BorderLayout ()); 
                add ("North",new Button ("Norden"));
		add ("South",new Button ("Süden"));
		add ("West",new Button ("Westen"));
		add ("East",new Button ("Osten"));
		add ("Center",new Button ("Stop"));
        }

}

Genauso wie auch beim FlowLayout gibt es eine Menge Einstellungen die man Setzen und ausgeben lassen kann.

Das GridLayout

Es teilt das Fenster in eine feste Anzahl Zeilen und Spalten. Über dieses gleichmäßige Gitter können nun alle Komponenten verteilt werden. Die Angabe der hor. und vert. Unterteilungen erfolgt beim initialisieren eines Objektes der Klasse. Auf den ersten Blich hat es vielleicht große Ähnlichkeit mit dem FlowLayout aber anhand des ersten Beispiels möchte ich sofort einen Unterschied aufzeigen.

Beispiel

import java.awt.*;

public class GridTest extends Frame {
	public static void main (String argv[]) {
	GridTest TestFrame = new GridTest ();
                TestFrame.resize (600,400);
                // Größe festlegen
                TestFrame.show ();
                // Fenster anzeigen
	}
	
	public GridTest () {
                        // Konstruktor
                super ("Testen des Grid Layouts");
		setLayout (new GridLayout (10,10)); 
		//setLayout (new GridLayout (10,10,10,10));
		// Legt noch die horizontalen u. vertikalen Abstände
		// der Komponenten fest
		for (int i=1;i<=100;i++)
                	add (new Button ("Test"+i));
        }

}

Wenn man jetzt die Größe des Fensters verändert, sieht man, daß die Button zwar ihre Größe verändern, aber immer in der gleichen Anordnung bleiben. Dies hat große Vorteile, wenn man ein Fensterlayout nicht sich selbst überlassen will.

GridBagLayout

Das GridBagLayout ist das Layout, welches in größeren Anwendungen fast immer verwendet wird. Es hat Ähnlichkeiten mit dem GridLayout, aber man kann die Rasterung des Fensters beliebig variieren. Um dies zu realisieren stehen eine Menge Instantzvariablen zum Verfügung:

  • gridx, gridy
    • gridwidth, gridhight
      • weigthx, weightx
        • fill
          • ipadx, apady
            • anchor

              Unverzichtbar bei der Arbeit mit dem GridBagLayout ist die Klasse GridBagConstraints. Sie birgt eine große Anzahl an vordefinierten Konstanten, die den Quellcode in seiner Lesbarkeit entscheidend verbessern.

              Beispiel 1

              import java.awt.*;
              
              public class GridBagTest extends Frame {
              	public static void main (String argv[]) {
              		GridBagTest TestFrame = new GridBagTest ();
                              TestFrame.resize (500,100);
                              // Größe festlegen
                              TestFrame.show ();
                              // Fenster anzeigen
              	}
              
              	public GridBagTest () {
              		super ("Test des GridBag Layouts");
              		GridBagLayout MyLayout = new GridBagLayout ();
              		GridBagConstraints MyConst = new GridBagConstraints ();
              		MyConst.fill = GridBagConstraints.NONE;
              		// Button behält immer Originalgröße
              		MyConst.weightx = 1;
              		MyConst.weighty = 1;
              		setLayout (MyLayout);
              		Button B1 = new Button ("B1"); 
              		MyConst.anchor = GridBagConstraints.NORTH;
              		// Ausrichtung nach oben
              		MyLayout.setConstraints (B1,MyConst);
              		Button B2 = new Button ("B2"); 
              		MyConst.anchor = GridBagConstraints.NORTHWEST;
              		// Ausrichtung nach oben links
              		MyLayout.setConstraints (B2,MyConst);
              		Button B3 = new Button ("B3");
              		MyConst.anchor = GridBagConstraints.NORTHEAST;
              		// Ausrichtung nach oben rechts 
              		MyLayout.setConstraints (B3,MyConst);
              		Button B4 = new Button ("B4"); 
              		MyConst.anchor = GridBagConstraints.SOUTH;
              		// Ausrichtung nach unten
              		MyLayout.setConstraints (B4,MyConst);
              		Button B5 = new Button ("B5");
              		MyConst.anchor = GridBagConstraints.SOUTHWEST;
              		// Ausrichtung nach unten links 
              		MyLayout.setConstraints (B5,MyConst);
              		Button B6 = new Button ("B6");
              		MyConst.anchor = GridBagConstraints.SOUTHEAST;
              		// Ausrichtung nach unten rechts 
              		MyLayout.setConstraints (B6,MyConst);
              		Button B7 = new Button ("B7");
              		MyConst.anchor = GridBagConstraints.WEST;
              		// Ausrichtung nach rechts 
              		MyLayout.setConstraints (B7,MyConst);
              		Button B8 = new Button ("B8");
              		MyConst.anchor = GridBagConstraints.EAST;
              		// Ausrichtung nach links 
              		MyLayout.setConstraints (B8,MyConst);
              		add (B1);
              		add (B2);
              		add (B3);
              		add (B4);
              		add (B5);
              		add (B6);
              		add (B7);
              		add (B8); 
              	}
              }
              

              Wenn man das Beispiel einmal startet, sieht es auf den ersten Blich aus, als währen die Button sinnlos im Fenster verteilt. Denkt man sich aber ein Raster von 8×1 Feldern, dann sieh man, daß die Button genau den Angaben der Variable anchor folgen. Der erste ist oben mittig in seiner Zelle, der zweite ist oben links und so weiter. Wenn man des Fenster jetzt noch in seiner Größe verändert, dann sieht man, das die Button ihre Größe (so weit es geht) nicht verändern. Trotz dem behalten sie ihre Position relativ zur Fenstergröße bei.

              Beispiel 2

              import java.awt.*;
              
              public class GridBagTest extends Frame {
              	public static void main (String argv[]) {
              		GridBagTest TestFrame = new GridBagTest ();
                              TestFrame.resize (300,100);
                              // Größe festlegen
                              TestFrame.show ();
                              // Fenster anzeigen
              	}
              
              	public GridBagTest () {
              		super ("Test des GridBag Layouts");
              		GridBagLayout MyLayout = new GridBagLayout ();
              		GridBagConstraints MyConst = new GridBagConstraints ();
              		MyConst.fill = GridBagConstraints.BOTH;
              		// Button behält immer Maximalgröße
              		MyConst.weightx = 1;
              		MyConst.weighty = 1;
              		setLayout (MyLayout);
              		Button B1 = new Button ("B1"); 
              		MyConst.gridwidth = 1;
              		MyConst.gridheight = 2;
              		MyLayout.setConstraints (B1,MyConst);
              		Button B2 = new Button ("B2"); 
              		MyConst.gridwidth = 1;
              		MyConst.gridheight = 1;
              		MyLayout.setConstraints (B2,MyConst);
              		Button B3 = new Button ("B3");
              		MyConst.gridwidth =GridBagConstraints.REMAINDER;
              		MyLayout.setConstraints (B3,MyConst);
              		Button B4 = new Button ("B4");
              		MyConst.weightx = 1;
              		MyConst.weighty = 0.5; 
              		MyLayout.setConstraints (B4,MyConst);
              		Button B5 = new Button ("B5");
              		MyConst.weightx = 1;
              		MyConst.weighty = 1;
              		MyLayout.setConstraints (B5,MyConst);
              		add (B1);
              		add (B2);
              		add (B3);
              		add (B4);
              		add (B5);
              	}
              }
              

              Das ist noch mal ein Beispiel, wie man die Komponenten in Mehreren Zellen unterbringt, und so sein Fenster gut aufteilen kann.

              Übung

              Tja mir will einfach keine geeignete Übung für diese Lektion einfallen, also schlage ich einfach mal vor, daß Du statt den Buttons einfach mal andere Komponenten wie z.B. Panels, Canvas, Choices und andere in die Beispiele einsetzt, und mal mit den Instanzvariablen herumexperimentierst.

              Tschüs bis zum nächsten mal, wo es um Dialoge und Menüs geht.


              Lektion 5

              Dies ist erst mal der letzte Teil, der sich mit der Programmierung der Benutzeroberfläche beschäftigen wird. Genauer gesagt wird es um Menüs und Dialoge gehen.
              Menüs und Dialoge sind ein wichtiger Bestandteil einer guten Benutzeroberfläche, und daher werde ich ihren Einsatz an einigen Beispielen erklären.
              Am ersten Beispiel kann man gut sehen ,wie man ein Menü in sein Programm einbindet.

              Beispiel 1

              import java.awt.*;
              
              public class Menue extends Frame {
              
              	public static void main (String argv[]) {
              		Menue MenuTest = new Menue ();
              		MenuTest.resize (200,200);
                              // Größe festlegen
                              MenuTest.show ();
                              // Fenster anzeigen
              	}
              
              	public Menue () {
              		super ("Tach");
              		Menu myMenu = new Menu ("Zeichne");
              		myMenu.add ("Kreis");
              		myMenu.add ("Rechteck");
              
              		MenuBar myMenuBar = new MenuBar ();
              		myMenuBar.add (myMenu);
              
              		setMenuBar (myMenuBar);
              	}
              }
              

              Bis jetzt haben die MenuItems noch nicht viel Sinn. Falls Du Dir den Kreis oder des Rechteck vor Deinem geistigen Auge vorstellen kannst ist das Programm schon fertig. Falls nicht dann kommt jetzt ein zweites Beispiel, welches dann die Aufgabe übernimmt deine Phantasie zu ersetzen:-))).

              Beispiel 2

              import java.awt.*;
              
              public class Menue extends Frame {
              		
              	boolean Kreis;
              	boolean Rechteck;
              
              	public static void main (String argv[]) {
              		Menue MenuTest = new Menue ();
              		MenuTest.resize (200,200);
                              // Größe festlegen
                              MenuTest.show ();
                              // Fenster anzeigen
              	}
              
              	public Menue () {
              		super ("Tach");
              		Menu myMenu = new Menu ("Zeichne");
              		myMenu.add ("Kreis");
              		myMenu.add ("Rechteck");
              
              		MenuBar myMenuBar = new MenuBar ();
              		myMenuBar.add (myMenu);
              
              		setMenuBar (myMenuBar);
              	}
              
              	public boolean action (Event e, Object o) {
              		if ("Kreis".equals(o)) {
              			Kreis = true;
              		}
              		if ("Rechteck".equals(o)) {
              			Rechteck = true;
              		}
              		repaint ();
              		return true;
              	}
              
              	public void paint (Graphics g) {
              		if (Rechteck) {
              			g.drawRect (70,80,80,90);
              			Rechteck = false;
              		}
              		if (Kreis) {
              			g.drawOval (100,120,40,40);
              			Kreis = false;
              		}
              	}
              }
              

              Hier wird mittels der action Methode abgefragt, welcher Menüeintrag ausgewählt wurde und der jeweilige Schalter auf true gesetzt. Dann noch ein repaint und fertig. Die Methode repaint ruft eigentlich nur die Methode paint auf und übergibt ihr den aktuellen Grafikkontext.
              Um das Programm jetzt noch zu perfektionieren benötigt man noch eine Hilfe:-))). Diese Hilfe wird aus einem Menü Hilfe mit einem MenuItem About bestehen. Dies ist dann ein Dialog der Name, Autor und Version des Programmes anzeigt.
              Dies wird im folgenden Beispiel mit Hilfe von 2 Klassen realisiert. Eine Klasse ist des „Hauptprogramm“ und eine weitere Klasse ist ein Dialog. Diesen Dialog kann man dann aus dem Menü Hilfe-About aus anzeigen lassen.

              Beispiel 3

              ------------------------ File ThisDialog.java -----------------
              import java.awt.*;
              
              public class ThisDialog extends Frame {
              	
              	TestDialog theDialog;
              	Menu Hilfe;
              	MenuBar Menuebar;
              	public static void main (String argv[]) {
              		ThisDialog myDialog = new ThisDialog ();
              		myDialog.resize (200,200);
              		myDialog.show ();		
              	}
              	
              	public ThisDialog () {
              		super ("Dialog");
              		Hilfe = new Menu ("Hilfe");
              		Hilfe.add ("About");
              		Menuebar = new MenuBar ();
              		Menuebar.add (Hilfe);
              		setMenuBar (Menuebar);
              		theDialog = new TestDialog (this,"Tach",true);
              	}
              	
              	public boolean action (Event e,Object o) {
              		if ("About".equals(o))
              			theDialog.show ();
              		return true;
              	}
              }
              ---------------------------------------------------------------
              ------------------------ File TestDialog.java -----------------
              import java.awt.*;
              
              public class TestDialog extends Dialog {
              	public TestDialog (Frame parent, String name, boolean m) {
              		super (parent,name,m);
              		resize (300,150);
              		add ("South",new Button ("OK"));
              	}
              	
              	public void showTest () {
              		show ();
              	}
              	
              	public boolean action (Event e,Object o) {
              		if ("OK".equals(o))
              			dispose ();
              		return true;
              	}
              	
              	public void paint (Graphics g) {
              		g.drawString ("MENÜ Demo V 0.1",100,50);
              		g.drawString (" von Michael Jentsch",100,100);
              	}
              }
              ---------------------------------------------------------------
              

              Dieses Programm kennt nur den Menüpunkt Hilfe-About. Die anderen Menüpunkte in dieses Programm einzufügen ist die Übungsaufgabe dieser Lektion. Siehe dazu weiter unten Übung 5.
              Die Klasse ThisDialog ist das ausführbare Programm. Es beinhaltet die main Funktion, und generiert das Hauptfenster. Die action Methode reagiert auf den Menüpunkt About und zeigt bei einer Aktivierung des Menüpunktes den Dialog TestDialog.
              TestDialog ist eine Klasse, die von der Dialogklasse abgeleitet wurde. Ihr Konstruktor Plaziert einen Text in der Titelzeile, legt die Größe fest und plaziert einen OK Button am unteren Rand.
              Die Methode paint schreibt die gewünschten Informationen in den Grafikkontext des Dialoges und action behandelt den OK Button. Wenn er geklickt wird, dann wird der Dialog entfernt.
              Jetzt hast Du einen groben Überblick über einige Oberflächenspezifische Klassen des AWT. z.B.

              • Layoutmanager(GridBagLayout, FlowLayout, GridLayout, BodrerLayout)
              • Choice
              • TextField
              • Button
              • Menu
              • Dialog

              Das Paket bietet aber noch viel mehr Möglichkeiten, die aber dann auch am Umfang eines solchen Kurses scheitern. Wenn Du Dich für detailliertere Informationen in dieser Richtung interessierst, dann muß ich Dich leider auf die Originaldokumentation von Sun verweisen.

              Übung 5

              Erst mal eine Antwort auf die Frage: Wo ist die Lösung zu Lektion 3 ?
              Du findest sie in Lösung 3
              Mit Hilfe von Menüs und Dialogen ist es möglich, wenn auch nur sehr unkomfortabel, einen Taschenrechner zu programmieren. Er sollte mindestens addieren, subtrahieren, multiplizieren und dividieren können. Ich stelle mir das so vor, es gibt eine Menü Rechne mit den Items Add, Sub, Mul und Div. Jeder Aufruf eines solchen Menüpunktes öffnet einen Dialog, der z.B. bei der Addition nach Summand 1 und Summand 2 fragt, das Ergebnis berechnet. Dieses Ergebnis soll dann im Hauptfenster angezeigt werden.

              Viel Spaß!
              Bis zum 10.06.1997


              Lösung zu Lektion 5

              ----------------------RechnerDialog.java-------------------------------
              import java.awt.*;
              
              public class RechnerDialog extends Frame {
                      
                      EingabeDialog theDialog;
              	// Dialog zur Eingabe von 2 Zahlen
                      Menu Rechnen;
                      MenuBar Menuebar;
              	// Das Menü mit den Einträgen für Add.,Sub.,...
              	TextField Result;
              	// Textfeld für des Ergebnis
              
                      public static void main (String argv[]) {
                              RechnerDialog myDialog = new RechnerDialog ();
              		// Initialisiert sich selbet.
                              myDialog.resize (100,100);
                              myDialog.show ();               
                      }
                      
                      public RechnerDialog () {
                              super ("Rechner");
                              Rechnen = new Menu ("Rechnen");
                              Rechnen.add ("Addition");
              		Rechnen.add ("Subtraktion");
              		Rechnen.add ("Multiplikation");
              		Rechnen.add ("Division");
                              Menuebar = new MenuBar ();
                              Menuebar.add (Rechnen);
                              setMenuBar (Menuebar);
              		Result = new TextField (20);
              		add (Result);
                      }
                      
                      public boolean action (Event e,Object o) {
                              if ("Addition".equals(o)) {
              			theDialog = new EingabeDialog (this,"Addition",true);
                                      theDialog.show ();
              			Result.setText ((theDialog.getW1()+theDialog.getW2())+"");
              		}
              		if ("Subtraktion".equals(o)) {
              			theDialog = new EingabeDialog (this,"Subtraktion",true);
                                      theDialog.show ();
              			Result.setText ((theDialog.getW1()-theDialog.getW2())+"");
              		}
              		if ("Multiplikation".equals(o)) {
              			theDialog = new EingabeDialog (this,"Multiplikation",true);
                                      theDialog.show ();
              			Result.setText ((theDialog.getW1()*theDialog.getW2())+"");
              		}
              		if ("Division".equals(o)) {
              			theDialog = new EingabeDialog (this,"Division",true);
                                      theDialog.show ();
              			try {
              				Result.setText ((theDialog.getW1()/theDialog.getW2())+"");
              			} catch (ArithmeticException f) {
              			Result.setText ("Division by sero");
              			}
              		}
                              return true;
                      }
              }
              -----------------------------------------------------------------------
              ------------------------EingabeDialog.java-----------------------------
              import java.awt.*;
              
              public class EingabeDialog extends Dialog {
              	
              	TextField Wert1;
              	TextField Wert2;
              
              	Integer W1;
              	Integer W2;
              
                      public EingabeDialog (Frame parent, String name, boolean m) {
                              super (parent,name,m);
                              resize (120,100);
              		add ("North",new Label ("  Wert1       Wert2"));
              		add ("West",Wert1 = new TextField (5));
              		add ("Center",Wert2 = new TextField (5));
                              add ("South",new Button ("OK"));
                      }
                      
                      public boolean action (Event e,Object o) {
                              if ("OK".equals(o)) {
              			try {
                              		W1 = new Integer (Wert1.getText ());
              			} catch (NumberFormatException f) {
              				W1 = new Integer (0);
              			}
              			try {
                             		 	W2 = new Integer (Wert2.getText ());
              			} catch (NumberFormatException f) {
              				W2 = new Integer (0);
              			}
              		        dispose ();
              		}
                              return true;
                      }
              
              	public int getW1 () {
              		return W1.intValue ();
              	}
              
              	public int getW2 () {
              		return W2.intValue ();
              	}
              }
              -----------------------------------------------------------------------
              

              Hier benutze ich 2 Klassen eine ist abgeleitet von Frame, und die andere von Dialog. Die Klasse RechnerDialog ist das Hauptprogramm. Sie beinhaltet das Menü zum auswählen der Mathematschen Operation und ein TextField in dem das Ergebnis dargestellt wird.
              Die Klasse EingabeDialog besitzt ein Label als ein kleines Infofeld, einen OK Button, der die Eingabe abschließt und 2 TextFelder für die Eingabe von 2 Werten. Diese Werte können durch Aufruf der Methoden getW1 und getW2 abgefragt werden. Die try { .. } catch (.. Blöcke bewirken ein abfangen der Exception, welche bei Eingabe von nicht Zahlen eintritt. Zusätzlich ist noch eine Ausnahmebehandlung für den Fall einer Division duch 0 in der action Methode eingebaut.

              Lektion 6

              Moderne Betriebssysteme schaffen es mehrere Programme gleichzeitig ablaufen zu lassen, obwohl ihnen nur 1 Systemprozessor zur verfügung steht. Gie geht denn so was?
              Richtig, es geht gar nicht. Desshalb benutzen diese Systeme einen Trick. Sie lassen die Programme immer nur stückchenweise ablaufen. Ein Stückchen vom Programm 1, dann eins vom Programm 2 usw. Wenn alle Programe durch sind fängt das ganze wieder von vorne an. Dem Benutzer erscheint es dann so, als wenn alles gleichzeitig passieren würde. Na ja, zumindest so lange man sein System nicht gnadenlos überlastet.
              Weiterhin ist es auch möglich in einem Programm mehrere Aufgaben quasi gleichzeitig ablaufen zu lassen. Dies wird mit Hilfe von Threads realisiert. Am Beispiel 1 kann man sich ein Bild davon machen, wie einfach das Prinzip der Threads in Java ist.

              Beispiel 1

              ------------------------------File Test.java--------------------------------
              import java.io.*;
              
              public class Test {
              	
              	static TestThread MyThread[] = new TestThread[10];
              	
              	public static void main (String argv[]) {
              		System.out.println ("Start");
              		for (int i=0;i<10;i++)
              			MyThread[i] = new TestThread(""+i);
              		for (int i=0;i<10;i++)
              			MyThread[i].start();
              	}
              }
              ----------------------------------------------------------------------------
              ---------------------File TestThread.java-----------------------------------
              import java.io.*;
              
              public class TestThread extends Thread {
              
              	String Text;
              	
              	public TestThread (String newText) {
              		Text=newText;
              	}
              
              	public void run () {
              		try {
              			sleep (Math.round (Math.random()*1000));
              		} catch (Exception e) {}
              		System.out.println (Text);
              	}
              	
              }
              ----------------------------------------------------------------------------
              

              Dieses sehr einfache Beispiel gibt die Zahlen von 0-9 in zufälliger Reihenfolge aus. Die Klasse Test initialisiert 10 Threads mit je einer Zahl von 0-9. Dann werden sie alle nacheinander gestartet. Wenn sie alle nacheinander ablaufen würden, dann würde jeder Aufruf eines TestThreads einen zufälligen Zeitraum warten und seine Zahl ausgeben. So aber warten sie paralell und geben nach der zufälligen Wartezeit ihren Wert aus. Natürlich kann man die maximale Wartezeit noch kürzer wählen, aber je kürzer sie ist, desto „unzufälliger“ wird der Zufall. Man muß schließlich bedenken, daß TestThread[0] einen zeitlichen Vorteil gegenüber TestThread[9] hat, da er vorher aufgerufen wurde. Und je kürzer man nun den Max.Zeitraum wählt, desto mehr fällt der Zeitunterschied zwischen dem ersten und dem letzten Aufruf ins Gewicht.
              Falls man also mal einen leicht manipulierbaren Zufallsgenerator benötigt, kann man einfach statt der 1000 eine Variable einsetzen, die man größer oder kleiner wählen kann:-)))).
              Die Klasse Thread, von der die Klasse TestThread erbt, stellt noch eine Anzahl verschiedener Methoden zur Verfügung, die zur Verwalung eines Threads sehr hilfreich sind. Hier eine Liste der in Version 1.0.2 zur Verfügung stehenden Möglichkeiten die ein Thread beinhaltet.

              • start ()
                Startet den Thread. (Code in dieser Methode wird noch sequentiell abgearbeitet.)
              • run ()
                Das eigentliche Programm, welches dann paralell läuft.
              • stop ()
                Ablauf des Thread ende,
              • sleep (long)
                Pause in Millisekunden.
              • sleep (long, int)
                Pause in Millisekunden (long) + Nanosekunden (int)
              • suspend ()
                Hält den Thread an bis er durch resume reaktiviert wird.
              • resume ()
                Reaktiviert einen Thread, der durch suspend angehalten wurde.
              • destroy ()
                Die Notbremse. Sie beendet den Thread ohne die Methode stop aufzurufen.

              Zusätzlich stehen noch eine Vielzahl anderer Methoden zur Verfügung, die hier aber nicht weiter erwähnt werden müssen.

              Übung 6

              Zu diesem Thema möchte ich mal keine Übung aufgeben. Statt dessen kannst Du Dich schon auf die nächste Lektion vorbereiten, wo es um das leidige Thema LISTEN geht. Falls ich es schaffe werde ich auch noch einfache Bäume anschneiden.
              Bis dann,


              Lektion 7

              Listen sind sehr hilfreiche und flexible Hilfsmittel, wenn es darum geht, große Datenmengen zu speichern und zu verwalten.
              Java verfügt nicht über die für verkettete Listen typischen Zeiger. Daher wird jedes Listenelement in einem Objekt einer Klasse dargestellt. Das hört sich jetzt vielleicht etwas umständlich an, ist aber im Grunde noch einfacher und vor allem auch viel Fehlerunanfälliger als die Realisierung mit Hilfe von „struct“ und Zeigern in C++.
              Am folgenden Beispiel kannst Du eine einfache Klasse sehen. Die Klasse Liste ist eine einfache Form einer Liste in Java. In dieser Klasse besitzt jedes Listenelement einen String. Es gibt die Methoden insert zum einfügen eines neuen Listenelementes, show zum anzeigen aller Listenelemente und delete, die ein Element aus der Liste entfernt(!!Das erste Element kann hier noch nicht gelöscht werden!!). Getestet wird die Klasse mit Hilfe einer 2ten Klasse, der Klasse TestListe. Hier wird zuerst ein Objekt der Klasse Liste erzeugt und dann werden beliebig viele Elemente eingefügt und angezeigt. Als nächstes wird ein Element der Liste gelöscht und dann zum Test noch einmal die Liste angezeigt.

              // Testklasse
              public class TestListe {
              	public static void main (String argv[]) {
              		Liste MyListe = new Liste ();
              		// Eine Liste erstellen
              		MyListe.insert ("Test1");
              		MyListe.insert ("Test2");
              		MyListe.insert ("Test3");
              		MyListe.insert ("Test4");
              		MyListe.insert ("Test5");
              		// Elemente in die Liste einfügen
              		MyListe.show ();
              		// Alle Elemente anzeigen
              		int xxx=MyListe.delete ("Test3");
              		// Ein Element der Liste löschen
              		MyListe.show();
              		// Alle Elemente anzeigen
              	}
              }
              
              // Die Klasse Liste. In ihr können belibieg viele ( nur durch den Hauptspeicher begrenzt) 
              // Elemente abgespeichert werden 
              public class Liste {
              	String Inhalt = null;
              	// Inhalt des Listenelementes
              	Liste Next = null;
              	// Speicher reservieren für ein weiteres Element der Liste
              	
              	public void insert (String Element) {
              	// Einfügen eines neuen Listenelementes
              		if (Inhalt == null) {
              			Inhalt = Element;
              			Next = new Liste ();
              		} else {
              			Next.insert (Element);
              		}
              	}
              
              	public void show () {
              	// Anzeigen aller Elemente
              		if (Inhalt != null) {
              			System.out.println (Inhalt);
              			Next.show ();
              		}
              	}
              
              	public int delete (String Element) {
              	// Löschen eines Elementes
              		if (Inhalt != null) {
              			if (Element.compareTo (Inhalt)==0) {
              				return 1;
              			} else {
              				if (Next.delete (Element) == 1) {
              					Next = Next.Next;
              					// Nächstes Element ist das übernächste Element
              				}
              				return 0;
              			}
              		}
              		return 0;
              	}
              }
              

              Ein Objekt der Klasse Liste enthält einen String und ein Objekt der Klasse Liste, welches aber erst dann erzeugt wird, wenn der Inhalt der Klasse voll ist. Die Methode insert fügt ein Element in die Liste ein. Wenn also noch kein Element im aktuellen Objekt existiert, dann wird der Text eingefügt, und ein Objekt Next erzeugt. Wenn aber schon ein Element in der Liste ist, dann kann man voraussetzen, das auch schon ein Objekt Next existiert, und es wird das gleiche im Objekt Next durchgeführt, bis das Ende der Liste erreicht wurde (Rekursiv).
              Die Methode show geht ähnlich vor. Sie prüft, ob schon ein Objekt Next existiert, wenn Ja dann zeigt sie den Inhalt des aktuellen Elementes an und ruft sich selbst im Element Next auf, wo dann wieder überprüft wird, ob das Objekt Next existiert …….
              In der Methode delete habe ich ein bißchen geschummelt. Hier wird wie auch oben rekursiv die Liste bis zum Ende durchlaufen. Falls aber vorher ein Element der Liste mit dem Übergabeparameter übereinstimmt, dann stoppt die Rekursion und es wird eine 1 an den vorhergehenden Aufruf der Methode delete zurückgegeben. Wenn aber eine 1 als Returnwert eintrifft, dann wird das Objekt Next auf das Objekt Next.Next ( also das übernächste Element) gesetzt. Natürlich klappt des erst ab dem 2ten Element, da bei einem Abbruch im ersten Objekt der Rückgabewert direkt an das Hauptprogramm übergeben wird, wo er nicht weiter verarbeitet wird.
              Was jetzt noch fehlt, ist die Möglichkeit die Daten auf der Festplatte zu speichern, und wieder zu laden, um auch nach einem Neustart die Daten zur Verfügung zu haben.
              Zu diesem Zweck gibt es den FileInputStream und den FileOutputStream im Paket Java.io. Der FileInputStream ist zum lesen einer Datei, und der FileOutputStream zum schreiben in einer Datei.
              Das sieht dann so aus:

              import java.io.*;
              
              public class Liste {
              	String Inhalt = null;
              	Liste Next = null;
              	
              	public void insert (String Element) {
              		if (Inhalt == null) {
              			Inhalt = Element;
              			Next = new Liste ();
              		} else {
              			Next.insert (Element);
              		}
              	}
              
              	public void show () {
              		if (Inhalt != null) {
              			System.out.println (Inhalt);
              			Next.show ();
              		}
              	}
              
              	public int delete (String Element) {
              		if (Inhalt != null) {
              			if (Element.compareTo (Inhalt)==0) {
              				return 1;
              			} else {
              				if (Next.delete (Element) == 1) {
              					Next = Next.Next;
              					// Nächstes Element ist das übernächste Element
              				}
              				return 0;
              			}
              		}
              		return 0;
              	}
              
              	public void write () {
              	// Öffentliche Methode Write 
              		try {
              			FileOutputStream out = new FileOutputStream ("Liste",true);
              			// File öffnen
              			if (Inhalt != null) {
              				out.write (Inhalt.getBytes());
              				// Element abspeichern
              				Next.write (out);
              				// Um das File nicht jedesmal neu öffnen zu müssen wird der 
              				// FileOutputStream einfach nicht mit übergeben
              			out.close ();
              			// File schließen
              			}
              		} catch (IOException e) {}
              	}
              
              	void write (FileOutputStream out) {
              		try {
              			if (Inhalt != null) {
              				out.write (Inhalt.getBytes());
              				Next.write (out);
              			}
              		} catch (IOException e) {}
              	}
              }
              

              So weit so gut.
              Es gibt hier 2 Methoden write. Die als public deklarierte Methode wird vom Testprogramm aus aufgerufen und erzeugt einen FileOutputStream, der dann an den folgenden Aufruf der nicht öffentlichen Methode write weitergereicht wird. So wird jedes Element in der Datei abgespeichert. Die Angabe von true im Konstruktor des FileInputStream ermöglicht es, an eine schon bestehende Datei anzuhängen. Falls noch keine Datei existiert, wird sie neu erzeugt.

              Übung 7

              Die Klasse Liste ist s noch nicht einsatzfähig, es fehlt
              1. Eine Methode zum einlesen der Daten und
              2. Die Delete Methode muß noch etwas bearbeitet werden.
              Hier noch ein Hinweis:
              Da die Stringelemente keine feste Länge besitzen, ist es sehr ratsam die Länge des Strings mit abzuspeichern, oder ein festes Trennzeichen zu definieren.
              Ich glaube das ist eine sinnvolle Aufgabe, um im Umgang mit verketteten Listen etwas vertrauter zu werden.


              Lösung zu Lektion 7

              public class TestListe {
              	public static void main (String argv[]) {
              		Liste MyListe = new Liste ();
              		MyListe.insert ("Test1");
              		MyListe.insert ("Test2");
              		MyListe.insert ("Test3");
              		MyListe.insert ("Test4");
              		MyListe.insert ("Test5");
              		MyListe.write ();
              		MyListe.delete ("Test1");
              		MyListe.delete ("Test2");
              		MyListe.delete ("Test3");
              		MyListe.delete ("Test4");
              		MyListe.delete ("Test5");
              		MyListe.show ();
              		MyListe.read ();
              		MyListe.show ();
              	}
              }
              _______________________________________________________
              import java.io.*;
              
              public class Liste {
              	String Inhalt = null;
              	Liste Next = null;
              	
              	public void insert (String Element) {
              		if (Inhalt == null) {
              			Inhalt = Element;
              			Next = new Liste ();
              		} else {
              			Next.insert (Element);
              		}
              	}
              
              	public String getRek () {
              		if (Inhalt != null) {
              			String XInhalt = new String (Inhalt);
              			Inhalt = Next.getRek();
              			return XInhalt;
              		} else {
              			return null;
              		}
              	}
              
              	public void show () {
              		if (Inhalt != null) {
              			System.out.println (Inhalt);
              			Next.show ();
              		}
              	}
              
              	public void delete (String Element) {
              		if (Inhalt != null) {
              			if (Element.compareTo (Inhalt)==0) {
              				Inhalt = Next.getRek();
              			} else {
              				Next.delete (Element);
              			}
              		}
              	}
              
              	public void write () {
              	// Öffentliche Methode Write 
              		try {
              			FileOutputStream out = new FileOutputStream ("Liste");
              			// File öffnen
              			if (Inhalt != null) {
              				out.write (Inhalt.length());
              				out.write (Inhalt.getBytes());
              				// Element abspeichern
              				Next.write (out);
              				// Um das File nicht jedesmal neu öffnen zu müssen wird der 
              				// FileOutputStream einfach nicht mit übergeben
              			out.close ();
              			// File schließen
              			}
              		} catch (IOException e) {}
              	}
              
              	void write (FileOutputStream out) {
              		try {
              			if (Inhalt != null) {
              				out.write (Inhalt.length());
              				out.write (Inhalt.getBytes());
              				Next.write (out);
              			}
              		} catch (IOException e) {}
              	}
              	
              	public void read () {
              		int Length;
              		try {
              			FileInputStream in = new FileInputStream ("Liste");
              			// File öffnen
              			if (Inhalt == null) {
              			// Am Ende der Liste anhängen
              				Length = in.read ();
              				// Lesen des ersten Bytes, hier steht die Länge
              				if (Length != -1) {
              					// Wenn -1 dann End Of File (EOF)
              					byte InArray[] = new byte[Length];
              					// Array von der Größe des Strings machen
              					in.read (InArray);
              					// Daten einlesen
              					Inhalt = new String (InArray);
              					// Umwandeln in einen String
              					Next = new Liste ();
              					// Neues Listenelement erzeugen
              					Next.read (in);
              					// Nächsten Eintrag lesen
              				} 
              			} else {
              				Next.read (in);
              			}
              			in.close ();
              		} catch (IOException e) {}
              	}
              
              	public void read (FileInputStream in) {
              		int Length;
              		try {
              			if (Inhalt == null) {
              			// Am Ende der Liste anhängen
              				Length = in.read ();
              				// Lesen des ersten Bytes, hier steht die Länge
              				if (Length != -1) {
              					// Wenn -1 dann End Of File (EOF)
              					byte InArray[] = new byte[Length];
              					// Array von der Größe des Strings machen
              					in.read (InArray);
              					// Daten einlesen
              					Inhalt = new String (InArray);
              					// Umwandeln in einen String
              					Next = new Liste ();
              					// Neues Listenelement erzeugen
              					Next.read (in);
              					// Nächsten Eintrag lesen
              				} 
              			} else {
              				Next.read (in);
              			}
              		} catch (IOException e) {}
              	}
              }
              

              Die Delete Methode habe ich total verändert. während in der 1ten Version einfach ein Element der Liste übergangen wurde, lasse ich jetzt den Inhalt aller Elemente vom Ende der Liste bis zu der frei gewordenen Stelle der Liste zum Anfang hin weiterreichen. Dadurch erreicht man, daß nun das Letzte Element der Liste überflüssig ist. Dieses kann einfach neu initialisiert werden, ohne sich um nachfolgende Listenelemente kümmern zu müssen.
              Die Write Methode wurde auch etwas geändert. Bevor ein Element in der Liste gespeichert wird, wird seine Länge abgespeichert. Dies ist unbedingt erforderlich, wenn man kein spezielles Trennzeichen definieren will.
              Die Read Methode ist neu. Sie öffnet zuerst das File und prüft dann den Inhalt des Listenelementes. Wenn das Element leer ist, wird ein Element aus dem File gelesen und in die Liste eingefügt. Jetzt wird noch neues Listenelement erzeugt und mit der Methode Read auch dieses Element gefüllt. Bis alle Elemente aus dem File gelesen wurden.
              Wenn das Listenelement nicht leer ist, dann wird sofort Next.read (in) aufgerufen, was bewirkt, daß die gleiche Prozedur für das nachfolgende Element durchgeführt wird.
              Methoden die eine Liste noch besitzen sollten sind z.B. eine Sortierfunktion, eine Suchfunktion und eine Prüfung beim einfügen, ob ein Element identisch ist, mit dem Element, welches eingefügt werden soll.
              Wer auf den Geschmack des sehr flexiblen Datentyps „Liste“ gekommen ist, dem wünsche ich viel Spaß. Es gibt noch eine unerschöpfliche Anzahl von Möglichkeiten Listen zu erweitern. Mit etwas Glück und Geschick kommt vielleicht mal eine Datenbank dabei heraus:-)).

              Lektion 8

              Diese Lektion hätte viel früher erscheinen müssen. Tja mein Fehler. Hier geht es nämlich um try und catch. Eine in einem try Block eingefaßte Methode kann keinen größeren Schaden anrichten. Denn falls ein Fehler auftritt, dann geht die Ausführung des Codes an einer Stelle weiter, wo man auf den Fehler eingehen kann. In Java gibt es 3 unterschiedliche Arten von Fehlerbehandlungen.
              1. Es wird von der Methode keine Fehlerbehandlung unterstützt2. Die Fehlerbehandlung ist möglich, aber nicht zwingend erforderlich3. Die Fehlerbehandlung ist zwingend erforderlich.
              Hier interessieren nur 2 und 3.
              Die Methoden die eine Exception unterstützen sind in der Plattform API gekennzeichnet.
              z.B.

              getBytes 
              
                public byte[] getBytes(String enc) throws UnsupportedEncodingException
              
                   Convert this String into bytes according to the specified character encoding, storing the result
                   into a new byte array. 
              
                   Parameters: 
                        enc - A character-encoding name 
                   Returns: 
                        The resultant byte array 
                   Throws: UnsupportedEncodingException 
                        If the named encoding is not supported 
              

              Hier wird die Exception UnsupportedEncodingException unterstützt. Das bedeutet an dieser Stelle nur, daß die gewählte Decodierung nicht unterstützt wird.
              Wenn Du Dir mal nicht sicher bist, ob oder welche Exception behandelt werden muß, dann compiliere einfach den Quellcode und Java sagt sofort wo und welche Exception erforderlich ist. Noch einfacher ist es, einfach den Teil des Codes wo man einen oder mehrere Fehler abfangen will, in einen try Block der mit catch (Exception e) {..} endet einzubinden. die Angabe von Exception bewirkt, das bei JEDEM Fehler der in diesem Teil auftritt in den Catch Block gesprungen wird.
              Wie Du ja schon in früheren Lektionen gesehen hast müssen Texteingaben in der Shell oder der Do?-Box in einem solchen try Block stehen, der mit einem catch (IOException e) {..} endet. Die IOException ist wie der Name schon ahnen läßt eine Ein/Ausgabe-Exception. sie fängt alle Fehler ab, die bei der Ein- oder Ausgabe auftreten können. Das bezieht sich nicht nur auf die Standart Ein-Ausgabe, sondern auch auf Files und auch auf die Kommunikation im Netzwerk.
              Eine nicht zwingend erforderliche Exception wird von Konstruktor MyInt = new Integer (String); der Klasse Integer ausgelöst, wenn der String nicht als Integerzahl interpretiert werden kann. Am folgenden Beispiel werde ich das noch etwas verdeutlichen.

              public class Fehler {
              	public static void main (String argv[]) {
              		Integer MyInt;
              		try {
              			MyInt = new Integer ("1234");
              			System.out.println (MyInt.toString());
              		} catch (NumberFormatException e) {
              			System.out.println (e);
              		}
              	}
              }
              ---------------------------------------------------------------------
              public class Fehler {
              	public static void main (String argv[]) {
              		Integer MyInt;
              			MyInt = new Integer ("1234");
              			System.out.println (MyInt.toString());
              	}
              }
              

              Beide Versionen sind lauffähig. Teste einfach mal, was passiert, wenn Du etwas an dem String änderst.
              Eine weitere seltener verwendete Variante ist die try brake finally Kombination. Diese in den meisten Fällen überflüssige Konstruktion erwähne ich hier nur zur Vollständigkeit:-). Wer so arbeitet landet schnell wieder beim Spaghetticode ….. und das im Zeitalter der Objektorientierten Programmierung.
              Falls während der Ausführung ein break in einem try Block auftritt, dann wird der Rest des try Blockes übergangen und die Ausführung geht im finally Block weiter.

              Beispiel

              public class Schrott {
              	try {
              		// Mache dies und mache jenes
              		if (...)
              			break;
              		// Mache dies und mache jenes
              	} finally {
              		// Code der ausgeführt wird, wenn break
              	}
              }
              

              Bis dann,


              Lektion 9

              Der Kurs neigt sich dem Ende, und ich hoffe, das Du von Dir sagen kannst, das Du etwas gelernt hast. Das Grundgerüst der Java Programmierung solltest Du mittlerweile verstanden haben und anwenden können. Sicherlich gibt es noch eine Vielzahl von Möglichkeiten, die auch noch in diesen Anfängerkurs gehört hätten. Sie sind entweder verschollen oder ich bin nicht drauf gekommen.
              Die letzten 2 Lektionen möchte ich für 2 spezielle Themengebiete nutzen. Dieser Kurs wird die einfache Netzwerkprogrammierung beinhalten, und im 10ten und letzten Kurs wird es um die Multimediafähigkeiten von Java gehen. Mit Multimedia & Java habe ich mich zwar noch nie befaßt, da es ja auch irgendwie einen Widerspruch in sich birgt. Deshalb wird sich der nächste Kurs evtl. auch wieder um ein paar Tage verschieben.

              Wenn Du ein Buch zur Netzwerkprogrammierung aufschlägst, dann wirst Du eine Menge über verschiedene Protokolle, OSI-Schichtenmodell, CRC Verfahren, Übertragungsgeschwindigkeiten, Netzwerkarchitekturen, DNS, TCP/IP, UDP, und eine Menge mehr lesen. Ich habe allerdings die Erfahrung gemacht, daß dies alles zwar sehr interessant ist, aber nicht unbedingt erforderlich, wenn man nicht in die tiefsten Abgründe der Netzwerkarchitektur eindringen will.
              Die wichtigsten Informationen für den Anwendungsprogrammierer sind meist in dem Wust verborgen, und wenn man sie mal braucht, dann findet man sie gerade nicht. Als Anfänger ist es natürlich nicht so leicht sich da durch zu Kämpfen und gibt dann auch schnell auf. In diesem Kurs werde ich am Beispiel eines Chatprogrammes die Grundlagen der Netzwerkprogrammierung erklären und hoffentlich ein wenig Licht ins Dunkel bringen.
              Beispiel 1 ist ein einfaches Kommunikationsprogramm. Die Client Server Architektur wird hier verdeutlicht.

              import java.net.*;
              import java.io.*;
              
              public class TalkServer {
              
              	public static void main (String argv[]) {
              		try {
              			String Zeile = new String ();
              			ServerSocket MyServer = new ServerSocket (4000);
                                      Socket MyClient = MyServer.accept();
                                      DataInputStream in = new DataInputStream (MyClient.getInputStream());
                                      while ((Zeile=in.readLine ())!=null) {
                                              System.out.println (Zeile);
                                              if (Zeile.equals ("")) {
                                                      break;
                                              }
                                      }
              			MyServer.close ();
              			MyClient.close ();
              		} catch (IOException e) {
              			System.out.println (e);
              		}
              	}
              }
              ------------------------------------------------------------------------
              import java.net.*;
              import java.io.*;
              
              public class TalkClient {
              
              	public static void main (String argv[]) {
              		try {
              			String Zeile = new String ();
                                      Socket MyClient = new Socket ("Hostname",4000);
              			// Hostname des Serverprogrammes
                                      PrintStream out = new PrintStream (MyClient.getOutputStream());
                                      DataInputStream in = new DataInputStream (System.in);
              			do {
                                              Zeile = in.readLine ();
              				out.println (Zeile);
                                      } while (!Zeile.equals (""));
              		} catch (IOException e) {
              			System.out.println (e);
              		}
              	}
              }
              

              Wenn Du dieses Programm testen möchtest, dann benötigst Du dazu ein TCP/IP Protokoll. Unixe haben so etwas standardmäßig installiert. Windosen nicht. Wer also mit Win95 oder WinNT arbeitet, muß ein TCP/IP Protokoll installieren. Wer keine Netzwerkkarte besitzt und trotzdem Netzwerkprogrammierung probieren möchte, der kann einfach ein DFÜ Medium als Grundlage für das Protokoll benutzen.
              Wenn das geschafft ist, dann muß der Hostname des Servers in Erfahrung gebracht werden.
              Unix > Hostname [Enter]Win95/NT in den Einstellungen>Systemsteuerung>Netzwerk den Namen des Computers anzeigen lassen.
              Wie immer habe ich auch hier keinen Schimmer wie das auf einem MAC funktioniert. Tut mir echt leid.

              Bemerkung: Wenn der Rechner über einen Onlinedienst z.B. Metronet mit dem Internet verbunden ist, dann ist in der Regel schon ein DFÜ Netzwerk installiert. Ausnahmen wie z.B. AOL bestätigen die Regel.
              Auch wenn Dein Rechner in einem LAN (Local Area Network) integriert ist, brauchst Du Dir um die Netzwerkinstallation keine Sorgen zu machen.

              Nun aber zum Programm. Den TalkServer ausführen, und nichts passiert. Das ist gut so. Der Server wartet jetzt darauf, das ein Client eine Verbindung anfordert (Socket MyClient = MyServer.accept()).
              Der Client muß wissen auf welchem Rechner das Serverprogramm ausgeführt wird. Also in der Zeile (Socket MyClient = new Socket („Hostname“,4000)) für Hostname den ermittelten Computernamen eintragen, neu compilieren und ausführen. Wenn auch hier kein Fehler auftritt, dann kannst Du jetzt einen Text eingeben, der über das Netz zum Server übertragen, vom TalkServer empfangen und ausgegeben wird.
              Bei Eingabe einer Leerzeile wird die Verbindung vom Server unterbrochen und beide Programme beendet.
              Alle Netzwerkprogramme folgen dieser Client Server Architektur. Die meisten geben zwar noch Daten an den Client zurück, aber das ändert nichts am Prinzip der Client Server Technik.

              Ein Chatprogramm verbindet 2 oder mehr Personen, um miteinander zu kommunizieren. Das hört sich nicht besonders an, hat es aber schon ein bißchen in sich, wenn man es mal genauer betrachtet.
              Wenn nicht festgelegt ist, wie viele Personen miteinander chatten, dann kann man entweder jeden mit jedem bekanntmachen, und die Daten nacheinander an alle User versenden, jeden nur mit seinen Nachbarn bekanntmachen, und die Daten in einem Ring weiterversenden, bis sie wieder am Erstsender angekommen sind oder man kann ein Serverprogramm und für jeden User einen Clienten schreiben. Dieser Server empfängt die Daten, und sendet sie an alle anderen User weiter. Die einfachste Methode ist wohl die Ringarchitektur.
              Hier ein einfaches Beispiel für eine 2 User Version

              import java.awt.*;
              import java.io.*;
              import java.net.*;
              
              public class Chat extends Frame {
              
              	CServer ChatServer;
              
              	Socket User2;
              	// Client Socket zum senden der Daten
              	PrintStream out;
              	// Stream der an den Socket gebunden wird
              
              	String UserHost;
              	// Hostname des entfernten Hosts
              
              	Button Connect;
              	Button Exit;
              	Button Send;
              	Label LKomm = new Label ("Kommunikationsfeld");
              	Label LEingabe = new Label ("Eingabefeld");
              	Label LStatus = new Label ("Statusfeld");
              	TextField Status;
              	TextField InField;
              	TextArea Kommunikat;
              	FlowLayout ThisLayout;
              	Panel Steuerung;
              	// Grafische Elemente 
              
              	public Chat () {
              		setResizable (false);
              		ThisLayout = new FlowLayout (FlowLayout.LEFT);
              		setLayout (ThisLayout); 
              		Connect = new Button ("Connect");
              		Exit = new Button ("Exit");
              		Send = new Button ("Send");
              		Status = new TextField (31);
              		InField = new TextField (55);
              		Kommunikat = new TextArea(10,55);
              		Kommunikat.setEditable(false);
              		Steuerung = new Panel ();
              		add (LEingabe);
              		add (InField);
              		add (LKomm);
              		add (Kommunikat);
              		add (LStatus);
              		Steuerung.add (Status);
              		Steuerung.add (Connect);
              		Steuerung.add (Send);
              		Steuerung.add (Exit);
              		add (Steuerung);
              		// Alle Komponennten auf dem Frame plazieren
              	}
              
              	public boolean action (Event e, Object o) {
              		if ("Exit".equals(o)) {
              			dispose ();
                                      System.exit (0);
                              }
              		// Button beenden
              
              		if ("Send".equals(o)) {
              			Kommunikat.append (InField.getText()+"\n");
              			out.println (InField.getText());
              			InField.setText ("");
              		}
              		// Button senden
              
              		if ("Connect".equals(o)) {
              			Login Log = new Login (this,"Host",true);
              			UserHost=Log.getHost ();
              			Status.setText ("Connect to "+UserHost);
              			Status.setText (Connect (UserHost));
              		}
              		// Button verbinden
              
              		return true;
              	}
              	
              	public String Connect (String toHost) {
              		try {
              			User2 = new Socket (toHost,4000);
              			// Verbinden mit dem Server von User 1
              			out = new PrintStream (User2.getOutputStream());
              			// Stream an den Socket binden
              			ChatServer = new CServer (Kommunikat,4100);
              			// eigenen Server starten
              			ChatServer.start ();
              		} catch (IOException e) {
              			// Falls keine Verbindung erstellt werden konnte
              			try {
              				// Eigenen Server als Server1 starten und auf eine Anfrage warten
              				ChatServer = new CServer (Kommunikat,4000);
              				ChatServer.start ();
              				// wenn eine Anfrage erfolgt ist dann an den fremden Socket binden
              				User2 = new Socket (UserHost,4100);
              				// und Stream an den Socket binden
              				out = new PrintStream (User2.getOutputStream());
              			} catch (IOException ex) {
              				return ("Connection refused");
              				// Verbindung ist nicht möglich 
              			}
              		}
              		return ("Connection OK");
              	}
              
              	public static void main (String argv[]) {
              		Chat User = new Chat ();
                              User.resize (440,370);
              		User.move (100,100);
                              // Größe festlegen
                              User.show ();
                              // Fenster anzeigen
              	}
              }
              
              class Login extends Dialog {
              // Dialog um einen entfernten Host festzulegen (modaler Dialog)
              
              	TextField Host;
              	Button OK;
              	
              	public Login (Frame parent,String name,boolean mod ) {
              		super (parent,name,mod);
              		resize (200,80);
              		move (100,100);
              		Host = new TextField (30);
              		OK = new Button ("OK");
              		setLayout (new BorderLayout());
              		add ("North",Host);
              		add ("South",OK);
              		show ();
              	}
              
              	public boolean action (Event e,Object o) {
              		if ("OK".equals(o)) {
              			dispose ();
              			// Dialog entfernen und Ressourcen wieder freigeben
              		}
              		return true;
              	}
              	
              	public String getHost () {
              		return (Host.getText ());
              	}
              }
              
              class CServer extends Thread {
              // Thread zum empfangen der Daten
              
              	ServerSocket User1;
              	Socket User2;
              
              	String Zeile;
              	TextArea Kommunikation;
              
              	public CServer (TextArea Out,int Port) {
              		try {
              			User1 = new ServerSocket (Port);
              			if (Port == 4000) {
              				// User 1 bekommt immer den Serverport 4000 zugewiesen
              				Out.append ("Du bist User 1. Warte auf User 2\n");
              			} else {
              				// User 2 bekommt immer den Serverport 4100 zugewiesen
              				Out.append ("Du bist User 2. User 1 wertet schon\n");
              			}
              			User2 = User1.accept();
              			// Verbindungsanforderung abwarten
              			Kommunikation = Out;
              		} catch (Exception e) {
              		}
              	}
              
              	public void run () {
              		try {
              			DataInputStream in = new DataInputStream (User2.getInputStream());
              			while ((Zeile=in.readLine ())!="Bye") {
              				Kommunikation.append (Zeile+"\n");
              				// Zeilenweises einlesen der Daten
               			}
              			User1.close ();
              			User2.close ();
              			// Verbindung beenden
              		} catch (IOException e) {}
              	}
              }
              

              Wie Du siehst ist das Programm schon ein wenig umfangreicher. Es erkennt, ob schon ein Chat Programm läuft, und verhält sich dementsprechend, um die Programme miteinander zu verbinden. Statt nur einer Client-Server Verbindung benutze ich hier 2 Client-Server Verbindungen, um gleichzeitig senden und empfangen zu können.
              Der Rest erklärt sich mehr oder weniger von selbst.

              Übung

              Was noch nicht funktioniert, ist ein automatisches beenden beider Programme, bei Eingabe von „Bye“. Ich habe schon einmal eine Überprüfung des übergebenen Strings eingebaut, die so aber noch nicht funktioniert.
              Eine weitere etwas einfachere Aufgabe währe es, den Connect Button nach einer erfolgreichen Verbindung zu deaktivieren, und statt dessen einen Text in der Statuszeile auszugeben.

              Viel Spaß


              Lektion 10

              Da es diesmal um Multimedia geht, begeben wir uns in die Welt der Applets.
              Eigentlich wollte ich das ja vermeiden, aber Java ist in diesem Bereich noch nicht annähernd konkurrenzfähig gegenüber einem guten C++ Compiler oder Assembler. Da hapert es noch zu sehr an der Geschwindigkeit. Und in der Welt der Applets gibt es praktisch keine Konkurrenz, außer vielleicht durch PlugIns, die aber dann wieder abhängig vom Betriebssystem sind.
              Ich denke das ist eine gute Entschuldigung dafür, sich in die Welt der Applets zu begeben.

              Das Medium um das es als erstes geht, ist des Image. Man kann es einfach aus dem Netz laden, und dann in seinem Applet in beliebiger Größe anzeigen.
              Das ganze sieht dann so aus.

              _______________________________________________________________________
              File Medium1.java
              _______________________________________________________________________
              import java.applet.*;
              import java.awt.*;
              
              public class Medium1 extends Applet {
              	Image img;
              	
              	public void init () {
              		img = getImage (getDocumentBase(),"x.jpg");
              	}
              
              	public void paint (Graphics g) {
              		g.drawImage (img,0,0,640,480,this);
              	}
              }
              _______________________________________________________________________
              File Medium1.html
              _______________________________________________________________________
              <html;>
              <applet; code="Medium1.class" width=640 height=480></applet>
              </html>
              

              Einfach (wie immer) Medium1.class, Medium1.html und das Image X.jpg in einem Verzeichniss ablegen, und im Net$cape Navigator das HTML Dokument anzeigen lassen oder „Appletviewer Medium1.html“ aufrufen. Der Appletviewer ist ein Bestandteil des JDK. Wenn man ihn benutzt, braucht man sich keine Gedanken um die Kompatibilität der benutzten Java Version und der des Net$cape Navigators zu machen.
              Ich glaube, es gibt nicht viele Möglichkeiten, ein JPEG codiertes Bild einfacher darzustellen, als mit diesen 11 Zeilen Java Code. Java bietet zusätzlich aber noch weitere Möglichkeiten, ein existierendes Bild zu manipulieren. Dazu wieder ein einfaches Beispiel:

              import java.applet.*;
              import java.awt.*;
              import java.awt.image.*;
              
              public class Medium1 extends Applet {
              	Image img,red;
              	
              	public void init () {
              		img = getImage (getDocumentBase(),"x.jpg");
              		ImageFilter filter = new RedFilter ();
              		ImageProducer prod = new FilteredImageSource (img.getSource(),filter);
              		red = this.createImage (prod);
              	}
              
              	public void paint (Graphics g) {
              		g.drawImage (red,0,0,640,480,this);
              	}
              }
              
              class RedFilter extends RGBImageFilter {
              	public RedFilter () {
              		canFilterIndexColorModel = true;
              	}
              	
              	public int filterRGB (int x, int y, int rgb) {
              		int a = rgb & 0xff000000;
              		// nur der alpha Anteil
              		int r = rgb & 0x00ff0000;
              		// nur rot Anteil 
              		return a|r;	
              		// Die Werte a und r OR verknüpfen
              	}
              }
              

              Und da war nur der rote Anteil noch sichtbar.
              Ich muß ja zugeben, es ist alles sehr langsam. Aber das ist der Tribut, den man im Moment noch zahlen muß, wenn man eine vom Betriebssystem unabhängige Anwendung (hier Applet) programmieren möchte.
              Im übrigen habe ich noch Hoffnung, daß sich das Gerücht bewahrheitet, was besagt, In+el wird kommende Prozessoren mit einem Java-Modus ausstattet. Damit währe es möglich parallel x86-Code und Java-Code auszuführen. [Zu lesen in INTERNET intern].
              Und wenn erst einer damit anfängt, dann sind die anderen auch immer schnell dabei.

              Nun aber zum Sourcecode. Alles wie gehabt, nur diesmal wird noch ein 2tes Image erzeugt. Das macht der ImageProducer. Er nimmt sich einfach nur das erste Bild, und filtert es mit Hilfe des neu erzeugten Filters.
              Der Filter den wir erzeugt haben, wir abgeleitet vom RBGImageFilter. Dieser Filter dient zur einfachen Manipulation der einzelnen Pixel eines Images, welches im RGB-Farbmodell vorliegen muß.
              In dem neu erzeugten Filter wird von jedem Pixel nur der alpha Anteil und der rot Anteil ausgewertet. So kommt man dann zu einem roten Bild.

              Das war’s zum Image. Jetzt kommt der AudioClip. Im Prinzip nicht komplizierter, als das laden und anzeigen eines Images. Die „Macher“ von Java haben sich aber auch echt Mühe gegeben, solche Feinheiten auszuarbeiten, um schnell Erfolge zu erleben.
              Beispiel zum AudioClip

              import java.applet.*;
              import java.net.*;
              
              public class Medium2 extends Applet {
              	AudioClip Sound;
              	
              	public void init () {
              		try {
              			Sound = getAudioClip (new URL(getDocumentBase (),"X.au"));
              			// AudioClip laden
              			Sound.play ();
              			// AudioClip abspielen
              		} catch (MalformedURLException e) {}
              	}
              }
              

              Das ist auch wieder ein Beispiel dafür, das es einfacher eigentlich schon nicht mehr geht.
              Hier kann man wieder das File Medium1.html verwenden. Die Klasse einfach umbenennen, und fertig.
              Zusätzlich zu play gibt es noch die Methoden:loop () > Spielt in einer Endlosschleife
              stop () > Stoppt das abspielen
              Das ist nicht viel, aber es reicht.

              Testbild
              Testgong

              Wenn Du Dich noch mit der Animation beschäftigen willst, dann viel Spaß. Für mich ist hier Schluß.
              Ich hoffe, es war trotz ein paar kleiner Schwierigkeiten und Verzögerungen etwas hilfreich beim erlernen von Java.
              Für Fragen und Anregungen stehe ich selbstverständlich auch in Zukunft zur Verfügung.

              Tschüs