Kamper Andreas Swinging Java eine Fachbereichsarbeit aus Informatik bei Prof. Mag. Peter Micheuz BG und BRG Völkermarkt Schuljahr 2001/2002 2 An dieser Stelle möchte ich mich recht herzlich bei meinem Informatikprofessor, Herrn Prof. Mag. Peter Micheuz, bedanken, der mich während der Erstellung meiner Fachbereichsarbeit tatkräftig unterstützt hat. 3 Inhaltsverzeichnis 1. Einleitung ............................................................................................................................... 5 1.1. Vorwort ............................................................................................................................. 5 1.2. Was ist JAVA? ................................................................................................................. 6 1.3. Was ist SWING? ............................................................................................................. 6 1.4. Geschichte ........................................................................................................................ 7 1.4.1. Entstehung und Entwicklung von JAVA ............................................................. 7 2. Einführung in Java und Objektorientierung .................................................... 8 2.1. Grundlagen von JAVA ................................................................................................... 8 2.1.1. 2.1.2. 2.1.3. 2.1.4. 2.1.5. Was ist das JDK? ................................................................................................. 8 Eigenschaften und Sprachmerkmale von JAVA ................................................. 9 Syntax ................................................................................................................ 10 Datentypen ......................................................................................................... 18 Ausdrücke .......................................................................................................... 20 2.2. Grundlagen der Objektorientierung ............................................................................ 21 2.2.1. 2.2.2. 2.2.3. 2.2.4. 2.2.5. 2.2.6. 2.2.7. 2.2.8. 2.2.9. Klassen................................................................................................................ Objekte................................................................................................................ Methoden ............................................................................................................ Konstruktoren ..................................................................................................... Destruktoren........................................................................................................ Strukturierung .................................................................................................... Vererbung ........................................................................................................... Modifier (Lebensdauer, Sichtbarkeit, Veränderbarkeit) ..................................... Interfaces............................................................................................................. 22 22 23 23 25 25 27 29 31 3. SWING ................................................................................................................................. 33 3.1. Grundlagen .................................................................................................................... 33 3.1.1. 3.1.2. 3.1.3. 3.1.4. 3.1.5. 3.1.6. 3.1.7. Abstract Windowing Toolkit ............................................................................. Vom AWT zum Swing ...................................................................................... Unterschiede AWT – Swing ............................................................................... Vorteile / Nachteile von Swing .......................................................................... Abhängigkeit Swing – AWT .............................................................................. Eigenschaften von SWING ................................................................................ Swing – Package Überblick ............................................................................... 33 37 37 38 38 39 40 4 3.2. Container ....................................................................................................................... 42 3.2.1. 3.2.2. 3.2.3. 3.2.4. 3.2.5. 3.2.6. JFrame ................................................................................................................ JRootPane .......................................................................................................... JWindow ............................................................................................................ JDialog ................................................................................................................ JComponent ....................................................................................................... Weitere Container .............................................................................................. 42 44 46 46 48 48 3.3. Komponenten ................................................................................................................ 49 3.3.1. 3.3.2. 3.3.3. 3.3.4. 3.3.5. 3.3.6. 3.3.7. Panels .................................................................................................................. 51 Label und Textfelder .......................................................................................... 51 Buttons ............................................................................................................... 52 Listen / Comboboxen ......................................................................................... 52 Schieberegler ...................................................................................................... 53 Menüs ................................................................................................................. 54 Weitere Komponenten ....................................................................................... 55 3.4. Look and Feel ................................................................................................................ 56 3.5. Model – View – Controller ........................................................................................... 58 3.6. Layout-Manager ............................................................................................................ 59 3.7. Event – Handling ........................................................................................................... 62 4. Beispielprogramme ........................................................................................................ 64 4.1. Millionenshow ................................................................................................................ 64 4.2. Browser .......................................................................................................................... 75 4.3. Lotto ............................................................................................................................... 80 5. Entwicklersoftware ........................................................................................................ 92 5.1. JBuilder .......................................................................................................................... 92 5.2. Forte4Java ..................................................................................................................... 94 5.3. JavaEditor ...................................................................................................................... 95 6. Literaturverzeichnis ...................................................................................................... 96 5 1. Einleitung 1.1 Vorwort Eigentlich hatte ich nie geplant eine Fachbereichsarbeit zu schreiben. Erst Anfang dieses Schuljahres kam ich, natürlich nicht zuletzt wegen der Anregungen meines Informatikprofessors, auf diese Idee. Professor Peter Micheuz schlug mir vor, über das Thema „Swinging Java“ zu schreiben. Mich persönlich interessiert diese Programmiersprache sehr und ich war von Anfang an begeistert. Höchstwahrscheinlich hätte ich mich sowieso in meiner Freizeit mit Java beschäftigt, also dachte ich mir, ich könnte doch gleich eine Fachbereichsarbeit schreiben. Zu Beginn hatte ich noch einige Bedenken, weil ich zuvor eigentlich noch keinerlei Java Kenntnisse hatte. Doch mit Hilfe guter Lernunterlagen konnte ich mich recht gut einarbeiten. Die Matura rückt immer näher und es ist viel zu tun. Die Weihnachtsferien und ein Großteil meiner Freizeit wurde genützt um an der Fachbereichsarbeit weiterzuarbeiten. Aber eines ist klar: Der Aufwand hat sich vollkommen gelohnt. Mit der Unterstützung meines Informatikprofessors konnte ich schließlich die Fachbereichsarbeit so umsetzen, wie ich sie geplant hatte. 6 1.2 Was ist JAVA? Java ist sowohl eine objektorientierte Programmiersprache in der Tradition von Smalltalk als auch eine klassische imperative Programmiersprache nach dem Vorbild von C. Mit einer großen Anzahl von anspruchsvollen Features wie Multithreading, strukturiertem Exceptionhandling oder eingebauten grafischen Fähigkeiten verfügt Java über eine Reihe interessanter Neuerungen auf dem Gebiet der Programmiersprachen. Um einem Missverständnis vorzubeugen: JavaScript ist nicht Java! JavaScript ist eine Skript-Sprache, die in HTML eingebettet werden kann und bei manchen Web-Browsern (Netscape, Internet-Explorer) die Ausführung von bestimmten Funktionen und Aktionen innerhalb des Web-Browsers bewirkt. Im Gegensatz zu Java ist JavaScript ! keine selbstständige Programmiersprache, ! nicht von der Browser-Version unabhängig, ! nicht mit den notwendigen Sicherheitsmechanismen ausgestattet. 1.3 Was ist SWING? Die Java Foundation Classes (JFC) Software erweitert das Abstract Windowing Toolkit (AWT: siehe Seite 33) mit einem umfassenden Satz von graphischen Bibliotheken. Swing ist ein Graphical User Interface (GUI) Komponenten Werkzeug, Teil der Java Foundation Classes (JFC), einbezogen in die Java 2 Plattform. Swing erleichtert das Einsetzen von Anwendungen mittels Bereitstellen eines gänzlich in Java geschriebenen Satzes von UserInterface Elementen. Swing Komponenten gestatten ein benutzerdefiniertes „Look and Feel“ ohne von einem konkreten „windowing system“ abhängig zu sein. Da Swing in der Java 2 Plattform enthalten ist, muss man es nicht downloaden oder installieren. 7 1.4 Geschichte 1.4.1 Entstehung und Entwicklung von JAVA Alles fing mit einer Mail des damals 25-jährigen Programmierers Patrick Naughton an den SUN-Chef Scott McNealy an. Naughton hatte angekündigt, das Unternehmen zu verlassen, um zu Next Computer, Inc. zu wechseln. Er war der Meinung, dass bei SUN einige sehr grundsätzliche Dinge nicht gut liefen. McNealy forderte ihn daraufhin auf, seine Kritik mit eventuellen Lösungsvorstellungen niederzuschreiben. Im Großen und Ganzen warf er SUN vor, auf dem besten Wege zu sein, sich mehr und mehr von seinen potentiellen Kunden und Anwendern zu entfernen. Er forderte Hard- und Software, die nicht nur von Akademikern und hochspezialisierten Profis, sondern von normalen Menschen angewendet werden konnte. Im Jahre 1991 arbeitete ein kleines Team unter der Leitung von James Gosling an einem Projekt, dessen Ziel es war, eine neue Programmiersprache zu entwickeln, die sich in besonderer Weise zur Programmierung von elektronischen Geräten der Konsumgüterindustrie eignen sollte - also zum Programmieren von Toastern, Kaffeemaschinen, Videogeräten, Decodern für Fernsehgeräte usw. Leider blieb der erhoffte Erfolg aus. 1993 wurde die Zielrichtung des Projekts geändert. Der Arbeitstitel des ursprünglichen Projektes “OAK” (Objekt Application Kernel wurde in “Java” umbenannt, was im Amerikanischen ein Synonym für guten Bohnenkaffee ist. Die neue Zielsetzung war folgende: eine Programmiersprache zu entwickeln, die sich in besonderer Weise zur Programmierung auf verschiedenen Rechnertypen im Internet eignen sollte. Seit 1995 bietet SUN den Kern eines Javaprogrammiersystems JDK (Java Development Kit) zusammen mit einer Implementierung des Java-Interpreters (Java Virtual Machine) kostenlos an. Die meisten kommerziellen Programmierumgebungen für Java nutzen das JDK als Kernsystem. Im Jahre 1995 wurde Java der Öffentlichkeit vorgestellt. Seitdem hat sich diese Programmiersprache schneller verbreitet als jede andere neue Programmiersprache der letzten Jahre. [Quelle: Guido Krüger: GoTo Java 2 und Heinz-Peter Gumm / Manfred Sommer: Einführung in die Informatik] 8 2. Einführung in Java und Objektorientierung 2.1 Grundlagen von Java 2.1.1 Was ist das JDK? Das Java Development Kit (JDK) umfasst die für die Erstellung und das Testen von JavaApplikationen und Applets notwendige Software, die Packages mit den zur Grundausstattung gehörenden Java-Klassen, und die Online-Dokumentation. Zur Software gehören der Java-Compiler, das Java Runtime Environment (die Java Virtual Machine) für die Ausführung von Applikationen, der Appletviewer für die Ausführung von Applets, ein Java-Debugger und verschiedene Hilfsprogramme. Die Online-Dokumentation umfasst eine Beschreibung aller Sprachelemente und aller Klassen des Application Program Interface API. Java ist eine relativ junge Programmiersprache und daher noch immer in Entwicklung, d.h. es kommen immer wieder neue Versionen mit Ergänzungen und Verbesserungen heraus: ! Die Urversion ist JDK 1.0 (1995). ! Im Jahr 1997 kam Version 1.1 heraus, das brachte sowohl Änderungen und neue Konzepte (bei den Methodennamen gemäß den Beans-Konventionen, beim EventHandling, bei den Text-Files) als auch Erweiterungen durch zusätzliche Packages (z.B. für Datenbanken). ! Ende 1998 kam Version 1.2 mit umfangreichen Erweiterungen (unter anderem Swing). ! Anfang 2000 folgte Version 1.3 mit Fehlerkorrekturen und PerformanceVerbesserungen. Seit Version 1.2 wird das JDK auch „Java-Plattform 2“ genannt # „Java 2 Software Development Kit (SDK)“ Das JDK erhält man kostenlos (z.B. zum Download über das Internet). [Quelle: Guido Krüger: GoTo Java 2 und Heinz-Peter Gumm / Manfred Sommer: Einführung in die Informatik] 9 2.1.2 Eigenschaften und Sprachmerkmale von JAVA Java wurde vollständig neu entworfen. Die Designer versuchten, die Syntax der Sprachen C und C++ soweit wie möglich nachzuahmen, verzichteten aber auf einen Großteil der komplexen und fehlerträchtigen Merkmale beider Sprachen. Das Ergebnis ihrer Bemühungen haben sie wie folgt zusammengefasst: »Java soll eine einfache, objektorientierte, verteilte, interpretierte, robuste, sichere, architekturneutrale, portable, performante, nebenläufige, dynamische Programmiersprache sein.« Javaprogramme sind portabel, sie können also ohne jede Änderung auf unterschiedlichen Rechnern eingesetzt werden. Dies ist eine Voraussetzung für die Integration von JavaAnwendungen, so genannten Applets, in Internet-Seiten. Für diesen Zweck besitzt Java spezielle Sicherheitsmechanismen. Javaprogramme sind für unterschiedliche Anwendungszwecke geeignet. Man kann kurze Testprogramme schreiben, die in einem einfachen Fenster ablaufen, aber auch komplette Anwendungen, so wie sie für heutige Grafikoberflächen typisch sind. Dort wo Software kommerziell entwickelt wird, hat Java rasch Fuß gefasst, weil es ein modernisiertes C++ ist. Diese Sprache hatte sich in den letzten Jahren zum Industriestandard entwickelt, daher fällt eine Umstellung auf Java nicht schwer. Im Allgemeinen ist Java eine sehr übersichtliche Sprache: In Java gibt es die meisten elementaren Datentypen, die auch C besitzt. Arrays und Strings sind als Objekte implementiert und sowohl im Compiler als auch im Laufzeitsystem verankert. Alle primitiven Datentypen sind vorzeichenbehaftet und in ihrer Größe exakt spezifiziert. Die Ausdrücke in Java entsprechen weitgehend denen von C und C++. Variablendeklarationen werden wie in C++ als Anweisungen angesehen und können an beliebiger Stelle innerhalb des Code-Parts eines Programms auftauchen Als OOP-Sprache besitzt Java alle Eigenschaften moderner objektorientierter Sprachen. Wie C++ erlaubt Java die Definition von Klassen, aus denen Objekte erzeugt werden können. Objekte werden dabei als Referenzdatentypen behandelt, die wie Variablen angelegt und verwendet werden können. 10 Das Speichermanagement in Java erfolgt automatisch. Ein Garbage-Collector, der als niedrigpriorisierter Hintergrundprozess läuft, sucht in regelmäßigen Abständen nach nicht mehr referenzierten Objekten und gibt den durch sie belegten Speicher an das Laufzeitsystem zurück. [Quelle: Guido Krüger: GoTo Java 2 und Heinz-Peter Gumm / Manfred Sommer: Einführung in die Informatik] 2.1.3 Syntaxgrundlagen Einfaches Programm public class Klassenname { public static void main (String[] args) { Anweisung1; Anweisung2; ... } } Beispiel: public class Hallo { public static void main (String[] args) { System.out.print("Hallo "); } } Anweisungen: Block – Anweisung { Anweisung1; Anweisung2; ... } Beispiel: { double neuerKontostand = kontostand - betrag; kontostand = neuerKontostand; } 11 Ein Block ist eine Zusammenfassung von Anweisungen, die nacheinander ausgeführt werden. Im Block gelten die Anweisungen als eine Einheit. Somit kann der Block auch Variablendeklarationen enthalten, wie z.B. lokale Variablen, die nur in diesem Block sichtbar sind. Die if-Anweisung if (Bedingung) Anweisung oder: if (Bedingung) anweisung1 else anweisung2 Beispiel: if (betrag <= kontostand) kontostand = kontostand - betrag; Die if-Anweisung wertet zunächst den Ausdruck aus. Die Anweisung wird nur dann ausgeführt, wenn das Ergebnis des Ausdrucks true ist. Andernfalls wird mit der ersten Anweisung nach der if-Anweisung fortgefahren. Mit der if-else-Anweisung gibt es eine weitere Verzweigung in Java. Falls der Ausdruck wahr ist, wird anweisung1 ausgeführt, andernfalls anweisung2. Eine der beiden Anweisungen wird also in jedem Fall ausgeführt. Switch - Anweisung switch (ausdruck) { case constant: anweisung; ... default: } Die switch-Anweisung ist eine Mehrfachverzweigung. Zunächst wird der Ausdruck ausdruck, der vom Typ byte, short, char oder int sein muss, ausgewertet. In Abhängigkeit vom Ergebnis 12 wird dann die Sprungmarke angesprungen, deren Konstante mit dem Ergebnis des Ausdrucks übereinstimmt. Die Konstante und der Ausdruck müssen dabei zuweisungskompatibel sein. Schleifen: Die while-Schleife while (Bedingung) Anweisung Beispiel: while (kontostand < 2 * anfangsstand) { jahr++; double zinsen = kontostand * zinssatz / 100; kontostand = kontostand + zinsen; } Zuerst wird der Testausdruck, der vom Typ boolean sein muss, geprüft. Ist er true, wird die Anweisung ausgeführt, andernfalls wird mit der ersten Anweisung hinter der Schleife weitergemacht. Nachdem die Anweisung ausgeführt wurde, wird der Testausdruck erneut geprüft usw. Die Schleife wird beendet, sobald der Test false ergibt. do –Schleife do anweisung; while (ausdruck); Die do-Schleife wird mindestens einmal ausgeführt, weil der Ausdruck erst danach überprüft wird. Ergibt der Ausdruck false, wird sie beendet. Die for- Schleife for (Initialisierung;Bedingung;Aktualisierung) { Anweisung } 13 Beispiel: for ( i = 1; i <= 20; i++ ) { double zinsen = kontostand * zinssatz / 100; kontostand = kontostand + zinsen; } Ablauf der Schleife: Ausführung einer Initialisierung; anschließend wiederholte Ausführung einer Anweisung und Aktualisierung eines Ausdrucks solange eine Bedingung wahr ist. ! Der init-Ausdruck dient dazu, Initialisierungen durchzuführen, die durch die Auswertung von Ausdrücken mit Nebeneffekten verursacht werden. Der Rückgabewert der Ausdrücke wird vollständig ignoriert. Der init-Teil darf auch aus mehreren Ausdrücken bestehen, wenn die einzelnen Teilausdrücke durch Kommata getrennt sind. Um einen Schleifenzähler zu erzeugen, muss der init-Teil eine Variablendeklaration enthalten. ! Der test-Teil wird, ähnlich wie bei der while-Schleife, am Anfang der Schleife ausgeführt, und die Schleifenanweisung wird nur ausgeführt, wenn die Auswertung des Testausdrucks true ergibt. ! Der update-Ausdruck dient dazu, den Schleifenzähler zu verändern. Er wird nach jedem Durchlauf der Schleife ausgewertet, bevor der Testausdruck das nächste Mal ausgewertet wird. Methoden-Aufruf objekt.methodenName(parameter) Beispiel: System.out.println("Hallo!"); Die Ausführung einer Methode (eines Objekts oder einer Klasse) wird veranlasst und die notwendigen Parameter zur Verfügung gestellt. 14 Objekt-Erzeugung new Klassenname ( parameter ) Beispiel: new Rectangele(5, 10, 20, 30); new Auto("Honda",1985); Ein neues Objekt wird erzeugt und mit den Konstruktions-Parametern initialisiert. Der Konstruktor gibt eine Referenz (einen Verweis, einen Zeiger) auf das konstruierte Objekt zurück. Import einer Klasse import packageName.KlassenName; Beispiel: import java.awt.Rectangle; Eine Klasse wird aus einem Package importiert. Variablen-Deklaration TypName variabenName; oder TypName variablenName = ausdruck; Beispiele: int summe; int wert = 8; Mit dieser Anweisung erfolgt die Festlegung einer neuen Variablen eines bestimmten Typs und – wenn erwünscht – auch die Zuweisung eines Anfangswerts („Initialisierung“). 15 Wertzuweisung variablenName = ausdruck; Beispiel: summe = summe + 25; Einer Variablen wird ein neuer Wert zugewiesen. Typ-Umwandlung( 'cast' ): (TypName) ausdruck; Beispiele: (int)(x+0.5); (int)Math.round(100 * f); Es erfolgt eine Typumwandlung eines Ausdrucks (unter Informationsverlust). Aufruf statischer Methoden KlassenName.methodenName(parameter) Beispiel: Math.round(3.14); Statische Methoden (Methoden, die nicht auf einem Objekt operieren) werden aufgerufen und passende Parameter werden eingesetzt. Konstanten-Deklaration final TypName variablenName = ausdruck; final TypName variablenName; 16 Beispiel: final double DOSEN_INHALT = 0.355; Eine Konstante eines bestimmten Typs wird definiert. Diese muss zwar nicht gleich initialisiert werden, aber man kann Konstanten nur einmal einen Wert zuweisen. Methoden Implementation public class KlassenName { ... zugriffsSpezifizierer rückgabeTyp methodenName(parameterTyp parameterName, ...) { Implementation } } Beispiel: public class BankKonto { ... public void einzahlen(double betrag) { kontoStand = kontoStand + betrag; } ... } Die Arbeitsweise einer Methode wird definiert. Daten-Feld Deklaration (Instanz-Variable) class KlassenName { ... ZugriffsSpezifizierer Typ Variablenname ; } Beispiel: public class BankKonto { ... private double kontostand; } Eine Variable, die in jedem Objekt einer Klasse vorhanden ist, wird deklariert. 17 Die return - Anweisung return ausdruck; oder return; Beispiel: public class BankKonto { public double getKontoStand() { return kontostand; } ... } Bewirkt das Beenden der Methode und die Rückgabe des Ausdrucks; d. h. der return-Wert wird der Wert des Methodenaufrufs im aufrufenden Programm. Konstruktor - Implementation class KlassenName { ... ZugriffsSpezifizierer KlassenName (parameterTyp parameterName, ... ) { .. Implementation des Konstruktors } } Beispiel: public class BankKonto { ... public BankKonto(double eroeffnungsKontostand) { kontostand = eroeffnungsKontostand; } ... } Das Verhalten eines Konstruktors wird festlegt. Konstruktoren werden gebraucht um neu erzeugte Objekte zu initialisieren. [Quelle: http://ada.rg16.asn-wien.ac.at/~javafs/indexjfs.html] 18 2.1.4 Datentypen Eingabezeichen: Java legt den neueren Zeichensatz Unicode zugrunde, der praktisch alle weltweit geläufigen Zeichensätze vereint. Ein Unicode-Zeichen ist 2 Byte, also 16 Bit, lang. Der Unicode ist mit den ersten 128 Zeichen des ASCII- und mit den ersten 256 Zeichen des ISO-8859-1Zeichensatzes kompatibel. Kommentare: In Java gibt es 3 Arten von Kommentaren: ! Einzeilige Kommentare beginnen mit // und enden am Ende der aktuellen Zeile. ! Mehrzeilige Kommentare beginnen mit /* und enden mit */. Sie können sich über mehrere Zeilen erstrecken. ! Dokumentationskommentare beginnen mit /** und enden mit */. Sie können sich ebenfalls über mehrere Zeilen erstrecken. Kommentare derselben Art sind nicht schachtelbar. Ein Java-Compiler akzeptiert aber einen einzeiligen innerhalb eines mehrzeiligen Kommentars und umgekehrt. Dokumentationskommentare dienen dazu, Programme im Quelltext zu dokumentieren. Mit Hilfe des Tools „javadoc“ werden sie aus der Quelle extrahiert und in ein HTML-Dokument umgewandelt Primitive Datentypen: Alle primitiven Datentypen in Java haben eine feste Länge, die von den Designern der Sprache ein für allemal verbindlich festgelegt wurde. Ein sizeof-Operator, wie er in C vorhanden ist, wird in Java daher nicht benötigt und ist auch nicht vorhanden. Typname Länge Wertebereich Standardwert boolean 1 true, false false char 2 Alle Unicode-Zeichen \u0000 byte 1 -27...27-1 0 short 2 -215...215-1 0 int 4 -231...231-1 0 long 8 -263...263-1 0 float 4 +/-3.40282347 * 1038 0.0 double 8 +/-1.79769313486231570* 10308 0.0 [Quelle: Guido Krüger: GoTo Java 2] 19 Java kennt die beiden IEEE-754-Fließkommatypen float (einfache Genauigkeit) und double (doppelte Genauigkeit). Die Länge beträgt 4 Byte für float und 8 Byte für double. Variablen: Variablen dienen dazu, Daten im Hauptspeicher eines Programms abzulegen und gegebenenfalls zu lesen oder zu verändern. In Java gibt es drei Typen von Variablen: ! Instanzvariablen, die im Rahmen einer Klassendefinition definiert und zusammen mit dem Objekt angelegt werden. ! Klassenvariablen, die ebenfalls im Rahmen einer Klassendefinition definiert werden, aber unabhängig von einem konkreten Objekt existieren. ! Lokale Variablen, die innerhalb einer Methode oder eines Blocks definiert werden und nur dort existieren. Eine Variable in Java ist immer typisiert. Sie ist entweder von einem primitiven Typ oder von einem Referenztyp. Mit Ausnahme eines Spezialfalls bei Array-Variablen, auf den wir später zurückkommen, werden alle Typüberprüfungen zur Compile-Zeit vorgenommen. Java ist damit im klassischen Sinne eine typsichere Sprache. Variablen können auf zwei unterschiedliche Arten verändert werden: ! durch eine Zuweisung ! durch einen Inkrement- oder Dekrement-Operator Arrays: Arrays in Java unterscheiden sich dadurch von Arrays in anderen Programmiersprachen, dass sie Objekte sind. Obwohl dieser Umstand in vielen Fällen vernachlässigt werden kann, bedeutet er dennoch: ! dass Array-Variablen Referenzen sind ! dass Arrays Methoden und Instanz-Variablen besitzen ! dass Arrays zur Laufzeit erzeugt werden 20 Dennoch bleibt ein Array immer eine (möglicherweise mehrdimensionale) Reihung von Elementen eines festen Grundtyps. Arrays in Java sind semidynamisch, d.h. ihre Größe kann zur Laufzeit festgelegt, später aber nicht mehr verändert werden Die Deklaration eines Arrays in Java erfolgt in zwei Schritten: ! Deklaration einer Array-Variablen ! Erzeugen eines Arrays und Zuweisung an die Array-Variable Die Deklaration eines Arrays entspricht syntaktisch der einer einfachen Variablen, mit dem Unterschied, dass an den Typnamen eckige Klammern angehängt werden: Beispiel: int[] a; double[] b; boolean[] c; 2.1.5 Ausdrücke Wie in den meisten anderen Programmiersprachen gehören auch in Java Ausdrücke zu den kleinsten ausführbaren Einheiten eines Programms. Sie dienen dazu, Variablen einen Wert zuzuweisen, numerische Berechnungen durchzuführen oder logische Bedingungen zu formulieren. Ein Ausdruck besteht immer aus mindestens einem Operator und einem oder mehreren Operanden, auf die der Operator angewendet wird. Nach den Typen der Operanden unterscheidet man numerische, relationale, logische, bitweise, Zuweisungs- und sonstige Operatoren. Jeder Ausdruck hat einen Rückgabewert, der durch die Anwendung des Operators auf die Operanden entsteht. Der Typ des Rückgabewerts bestimmt sich aus den Typen der Operanden und der Art des verwendeten Operators. 21 2.2 Grundlagen der Objektorientierung Programmsysteme kann man auf zweierlei Weise strukturieren: 1. Durch eine funktionale Abstraktion: d. h. in dem das gesamte Programm als ein großer Algorithmus aufgefasst wird, der durch Verfeinerung der Algorithmen bis auf elementare Anweisungen zerlegt wird. Prozeduren werden in Unterprozeduren mit Unterprozeduren (usw.) zerlegt. Daten und Algorithmen werden getrennt behandelt. Bei größeren Programmsystemen führt diese Art aber zu erheblichen Problemen. 2. Durch Datenabstraktion: d. h. die Datenstrukturen stehen im Mittelpunkt der Betrachtung und sie haben eigene Algorithmen zur Verfügung, die sie zur Erledigung ihrer Aufgaben und Änderung ihres Zustands benötigen. Diese Sichtweise ist Grundlage der objektorientierten Programmierung(OOP). Der entscheidende Unterschied liegt darin, dass bei OOP die Objekte sozusagen „ein Gedächtnis“ haben, also immer den Zustand ihrer Daten kennen. Die grundlegenden Prinzipien von OOP sind Abstraktion, Kapselung, Modularisierung und Hierarchie. Nicht Prozeduren und Funktionen wie bei der ablauforientierten strukturierten Programmierung bilden das Gerüst des Systems, sondern Objekte und Objekttypen (Klassen), die Eigenschaften und eigene Operationen (Methoden) besitzen. Ein Programmsystem kann damit aus Objekten zusammengebaut werden, die miteinander in Verbindung stehen und sich gegenseitig Aufträge zusenden. Jedes Objekt erledigt damit einen und nur den Teil der Aufgaben, für den es verantwortlich ist. Das Zusammenwirken aller beteiligten Objekte löst die Gesamtaufgabe. [Quelle: http://www.oszhdl.be.schule.de/gymnasium/faecher/informatik] 22 2.2.1 Klassen Eine Klassendefinition in Java wird durch das Schlüsselwort class eingeleitet. Anschließend folgt innerhalb von geschweiften Klammern eine beliebige Anzahl an Variablen- und Methodendefinitionen. public class Tier { public String art; public int geburtsjahr; public int gewicht; } Diese Klasse ist methodenlos. Sie enthält lediglich die Variablen art, geburtsjahr und gewicht. Diese Variablen werden meist als Membervariablen bezeichnet. 2.2.2 Objekte Um von einer Klasse ein Objekt anzulegen, muss eine Variable vom Typ der Klasse deklariert und ihr mit Hilfe des new-Operators ein neu erzeugtes Objekt zugewiesen werden: Tier saeugetier; saeugetier = new Tier (); Die erste Anweisung ist eine normale Variablendeklaration. Die zweite Anweisung generiert mit Hilfe des new-Operators eine neue Instanz der Klasse Tier und weist sie der Variablen saeugetier zu. In Java wird jede selbst definierte Klasse mit Hilfe des new-Operators instanziert. Die beiden Anweisungen kann man auch kombinieren: Tier saeugetier = new Tier (); Zunächst haben alle Variablen Standardwerte. So kann man den Variablen Werte zuweisen: saeugetier.name = "Katze"; saeugetier. geburtsjahr = 1992; saeugetier. gewicht = 4; 23 2.2.3 Methoden Methoden definieren das Verhalten von Objekten. Sie werden innerhalb einer Klassendefinition angelegt und haben Zugriff auf alle Variablen des Objekts. Methoden ähneln den Funktionen anderer Programmiersprachen, jedoch arbeiten sie immer mit den Variablen des aktuellen Objekts. Wir berechnen das Alter dieses Tieres: public class Tier { public String name; public int geburtsjahr; public int gewicht; public int alter() { return 2002 - geburtsjahr; } } Der Aufruf einer Methode (in diesem Fall der Methode alter) könnte so erfolgen: Tier saeugetier= new Tier (); saeugetier. geburtsjahr = 1992; System.out.println(saeugetier.alter()); Das Programm würde „10“ auf dem Bildschirm ausgeben. 2.2.4 Konstruktoren In jeder objektorientierten Programmiersprache lassen sich spezielle Methoden definieren, die bei der Initialisierung eines Objekts aufgerufen werden: die Konstruktoren. In Java werden Konstruktoren als Methoden ohne Rückgabewert definiert, die den Namen der Klasse erhalten, zu der sie gehören. Konstruktoren dürfen eine beliebige Anzahl an Parametern haben und können überladen werden. 24 Als Beispiel erweitern wir die Klasse Tier um einen Konstruktor: public class Tier { public String name; public int geburtsjahr; public int gewicht; public Tier (String name) { this. name = name; } } Bei this handelt es sich um einen Zeiger, der beim Anlegen eines Objekts automatisch generiert wird. this ist eine Referenzvariable, die auf das aktuelle Objekt zeigt und dazu verwendet wird, die eigenen Methoden und Instanzvariablen anzusprechen. Der this-Zeiger ist auch explizit verfügbar und kann wie eine ganz normale Objektvariable verwendet werden. Wenn wir jetzt ein Objekt instanzieren wollen, müssen wir die Argumente wie bei einem Methodenaufruf in Klammern nach dem Namen des Konstruktors angeben: Tier saeugetier = new Tier ("Katze"); System.out.println(saeugetier.name); In diesem Fall wird zunächst Speicher für das Tier-Objekt beschafft und dann der Konstruktor aufgerufen. Dieser initialisiert seinerseits die Instanzvariable name mit dem übergebenen Argument „Katze“. Der nachfolgende Aufruf gibt dann diesen Text am Bildschirm aus. Unterschiedliche Konstruktoren können in Java auch problemlos verkettet werden. Das hat den Vorteil, dass der vorhandene Code wieder verwendet wird. Der aufzurufende Konstruktor wird dabei als eine normale Methode angesehen, die über den Namen „this“ aufgerufen werden kann. public Tier (String name, int geburtsjahr, int gewicht) { this(name); this. geburtsjahr = geburtsjahr; this. gewicht = gewicht; } 25 Beim Instanzieren eines neuen Objekts werden die Initialisierungschritte in einer genau festgelegten Reihenfolge ausgeführt: ! Zunächst werden die Superklassenkonstruktoren aufgerufen. ! Anschließend werden alle Membervariablen in der Reihenfolge ihrer Deklaration initialisiert. ! Schließlich wird der Programmcode im Rumpf des Konstruktors ausgeführt. 2.2.5 Destruktoren Neben Konstruktoren, die während der Initialisierung eines Objekts aufgerufen werden, gibt es in Java auch Destruktoren. Sie werden unmittelbar vor dem Zerstören eines Objekts aufgerufen. Ein Destruktor wird als geschützte (protected) parameterlose Methode mit dem Namen finalize definiert: protected void finalize() { ... } Destruktoren sind aber nicht so bedeutend wie in anderen objektorientierten Sprachen. Der Grund dafür ist, dass Java über ein automatisches Speichermanagement verfügt Anders als etwa in C++ muss man sich nicht um die Rückgabe von belegtem Speicher kümmern. 2.2.6 Strukturierung In großen Programmsystemen reichen Klassen als Strukturelemente alleine nicht aus. Aus diesem Grund bietet Java mit den Packages (Paketen) eine weitere Kollektion für Programmelemente an. Ein Paket ist eine Sammlung von Klassen, jede Klasse in Java ist Bestandteil eines Pakets. Paketnamen können aus mehreren Teilen bestehen und beliebig tiefe Hierarchien ausdrücken. 26 Der Name einer Methode oder einer Variablen besteht damit grundsätzlich aus drei Elementen: ! Paketname ! Klassen- oder Objektname ! Methoden- bzw. Variablenname Damit eine Klasse verwendet werden kann, muss angegeben werden, in welchem Paket sie liegt. Hierzu gibt es zwei unterschiedliche Möglichkeiten: 1.) Die Klasse wird über ihren vollen Namen angesprochen: java.util.Date d = new java.util.Date(); 2.) Am Anfang des Programms werden die gewünschten Klassen mit Hilfe einer importAnweisung eingebunden: import java.util.*; ... Date d = new Date(); Die Verwendung voll qualifizierter Namen hat den Nachteil, dass die Klassennamen sehr lang und unhandlich werden. Bequemer ist daher die Anwendung der zweiten Variante, bei der die benötigten Klassen mit Hilfe einer import-Anweisung dem Compiler bekannt gemacht werden. Die import-Anweisung gibt es ebenfalls in zwei unterschiedlichen Ausprägungen: 1.) Mit der Syntax import Paket.Klasse; wird genau eine Klasse importiert. Alle anderen Klassen des Pakets bleiben unsichtbar: import java.util.Date; ... Date d = new Date(); java.util.Vector = new java.util.Vector(); 27 2.) Unter Verwendung der Syntax import Paket.*; können alle Klassen des angegebenen Pakets auf einmal importiert werden: import java.util.*; ... Date d = new Date(); Vector v = new Vector(); 2.2.7 Vererbung Neben der Möglichkeit, Variablen und Methoden zu Klassen zusammenzufassen, ist die Vererbung, also die Möglichkeit, Eigenschaften vorhandener Klassen auf neue Klassen zu übertragen, ein weiteres wesentliches Designmerkmal objektorientierter Programmiersprachen. Fehlt diese Fähigkeit, bezeichnet man die Sprache auch als lediglich objektbasiert. Obwohl es eigentlich Mehrfachvererbung) gibt, zwei ist Möglichkeiten in Java nur der Vererbung Einfachvererbung (einfache möglich. Vererbung, Bei der Einfachvererbung wird eine Klasse von maximal einer anderen Klasse abgeleitet. Aber Java ist keineswegs eingeschränkt in diesem Bereich, denn mit Hilfe von Interfaces ist eine neue Art der Mehrfachvererbung möglich. Vererbung ist in Java, und natürlich auch in anderen Programmiersprachen, nur eine Möglichkeit, um das konkrete Problem in den Computer zu übertragen. Das Prinzip der Vererbung ist dann anwendbar, wenn zwei Objekte in einer „ist-ein“ oder „ist eine Art von“ Beziehung zueinander stehen. Eine abgeleitete Klasse ist ein Subtyp der zugehörigen Oberklasse, besitzt also deren Eigenschaften (Daten und Methoden) und erweitert diese bei Bedarf um neue. Ableiten einer Klasse: Wenn man eine neue Klasse aus einer bestehenden ableiten möchte, muss man im Kopf der Klasse mit Hilfe des Schlüsselworts extends einen Verweis auf die Basisklasse angeben. Dadurch erbt die abgeleitete Klasse alle Eigenschaften der Basisklasse, d.h. alle Variablen und alle Methoden. Durch Hinzufügen neuer Elemente oder Überladen der vorhandenen kann die Funktionalität der abgeleiteten Klasse erweitert werden. 28 class Saeugetier extends Tier { boolean gefaehrlich; } Wir können nun nicht nur auf die gefaehrlich verfilmt zugreifen, sondern auch auf alle Elemente der Basisklasse Tier: Saeugetier raubtier = new Saeugetier (); raubtier.name = "Tiger"; raubtier.geburtsjahr = 1985; raubtier.gewicht = 150; raubtier. gefaehrlich = true; System.out.println("Alter = "+ raubtier.alter()); Die Vererbung von Klassen kann beliebig tief geschachtelt werden. Eine abgeleitete Klasse erbt dabei jeweils die Eigenschaften der unmittelbaren Vaterklasse, die ihrerseits die Eigenschaften ihrer unmittelbaren Vaterklasse erbt usw. Besitzt eine Klasse jedoch das Attribut final, ist es nicht erlaubt, eine neue Klasse aus ihr abzuleiten. Tier Fisch ... Reptil Säugetier Raubtier ... Katze ... Nagetier Maus ... ... Huftier Pferd ... Die Superklasse ist die Klasse Tier. Aus ihr werden die drei Klassen Fisch, Reptil und Säugetier abgeleitet. Aus der Klasse Säugetier werden wiederum die Klassen Raubtier, Nagetier und Huftier abgeleitet. Und schlussendlich werden noch aus diesen drei Klassen weitere Unterklassen abgeleitet. Jede Klasse, die keine extends-Klausel besitzt, wird direkt aus Object abgeleitet. Jede explizit abgeleitete Klasse stammt am oberen Ende ihrer Vererbungslinie von einer Klasse ohne explizite Vaterklasse ab und ist damit ebenfalls aus Object abgeleitet. Object ist also die Superklasse aller anderen Klassen. 29 Überlagern von Methoden: Eine abgeleitete Klasse erbt nicht nur die Membervariablen, sondern auch alle Methoden der Vaterklasse. Es dürfen neue Methoden hinzugefügt werden und auch geerbte Methoden dürfen neu definiert werden. Dies nennt man Überlagerung von Methoden. Nach einer Überlagerung wird bei einem Aufruf der Methode immer die überlagerte Methode verwendet. Als einfaches Beispiel erweitern wir die Klasse Saeugetier um die Methode alter und geben das Alter in Monaten aus: class Saeugetier extends Tier { boolean gefaehrlich; public int alter() { return 12 * (2002 - geburtsjahr); } } Da die Methode alter schon in der Vaterklasse vorhanden ist, handelt es sich um eine Überlagerung. In Zukunft würde in allen Objekten von Typ Saeugetier beim Aufruf der Methode alter die überlagerte Version (also in Monaten berechnet) verwendet werden. Wird eine Methode x in einer abgeleiteten Klasse überlagert, wird die ursprüngliche Methode x verdeckt. Aufrufe von x beziehen sich immer auf die überlagernde Variante. Oftmals ist es allerdings nützlich, die verdeckte Superklassenmethode aufrufen zu können. In diesem Fall kann mit Hilfe des Ausdrucks super.x() die Methode der Vaterklasse aufgerufen werden. ! Methoden vom Typ private sind in abgeleiteten Klassen nicht sichtbar und können daher nicht überlagert werden. ! Bei Methoden vom Typ final deklariert der Anwender explizit, dass sie nicht überlagert werden sollen. ! Auch bei static-Methoden, die ja unabhängig von einer Instanz existieren, besteht das Problem nicht. 30 2.2.8 Modifier In jedem Java-Programm werden bestimmte Programmelemente zusammen mit Schlüsselwörtern wie public oder private verwendet. Mit Hilfe dieser Attribute können die Eigenschaften von Klassen, Methoden und Variablen verändert werden. Sie haben insbesondere Einfluss auf die Lebensdauer, Sichtbarkeit und Veränderbarkeit dieser Programmelemente und werden meist als Modifier bezeichnet. Mittels der Sichtbarkeit kann auch der Zugriff auf Methoden und Variablen der Basisklasse eingeschränkt werden. Die Sichtbarkeit von Variablen und Methoden wird mit Hilfe folgender Modifier geregelt: public: Elemente des Typs public sind in der Klasse selbst (also in ihren Methoden), in Methoden abgeleiteter Klassen und für den Aufrufer von Instanzen der Klasse sichtbar. protected: Methoden oder Variablen vom Typ protected sind in der aktuellen Klasse und in abgeleiteten Klassen sichtbar. Darüber hinaus sind sie für Methoden anderer Klassen innerhalb desselben Pakets sichtbar. Sie sind jedoch nicht für Aufrufer der Klasse sichtbar, die in anderen Paketen definiert wurden. private: Methoden oder Variablen vom Typ private sind nur in der aktuellen Klasse sichtbar, in allen anderen Klassen bleiben sie dagegen unsichtbar. Elemente, die ohne einen der drei genannten Modifier deklariert wurden, werden als „package scoped“ oder Elemente mit Standard-Sichtbarkeit bezeichnet. Sie sind nur innerhalb des Pakets sichtbar, zu dem diese Klasse gehört. In anderen Paketen sind sie dagegen unsichtbar. static: Variablen und Methoden mit dem Attribut static sind nicht an die Existenz eines konkreten Objekts gebunden, sondern existieren vom Laden der Klasse bis zum Beenden des Programms. Das static-Attribut beeinflusst bei Membervariablen ihre Lebensdauer und erlaubt bei Methoden den Aufruf, ohne dass der Aufrufer ein Objekt der Klasse besitzt, in der die Methode 31 definiert wurde. Wird das Attribut static nicht verwendet, so sind Variablen innerhalb einer Klasse immer an eine konkrete Instanz gebunden. final: Membervariablen mit dem Attribut final dürfen nicht verändert werden, sind also als Konstanten anzusehen. Methoden des Typs final dürfen nicht überlagert werden; ebenso wenig dürfen Klassen des Typs final zur Ableitung neuer Klassen verwendet werden. 2.2.9 Interfaces Wie schon vorhin erwähnt, gibt es in Java keine Mehrfachvererbung von Klassen. Andererseits wäre es vorteilhaft, wenn Klassen eine oder mehrere Schnittstellendefinitionen erben können, und so haben die Designer mit den Interfaces ein Ersatzkonstrukt geschaffen, das dieses Feature bietet. Definition und Implementierung: Ein Interface ist eine besondere Form einer Klasse, die ausschließlich abstrakte Methoden und Konstanten enthält. Anstelle des Schlüsselwortes class wird ein Interface mit dem Bezeichner interface deklariert. Alle Methoden eines Interfaces sind implizit abstrakt und öffentlich. Als Beispiel definieren wir ein Interface Groesse, das die zwei Methoden laenge und hoehe enthält: public interface Groesse { public int laenge(); public int hoehe(); } Um die gewünschte Funktionalität zu erhalten, muss das Interface von einer Klasse implementiert werden. Dazu wird die class-Anweisung um eine implements-Klausel erweitert. Als Beispiel bauen wir dieses Interface in die Tier-Klasse ein: public class Tier implements Groesse { 32 public String name; public int geburtsjahr; public int gewicht; public int laenge; public int hoehe; public int laenge() { return this.laenge; } public int hoehe() { return this.hoehe; } } Wir haben die Klasse dazu um zwei veränderliche Instanzmerkmale erweitert, die es uns erlauben, die vom Interface geforderten Methoden auf einfache Weise zu implementieren. Nützlich ist ein Interface immer dann, wenn Eigenschaften einer Klasse beschrieben werden sollen, die nicht direkt in seiner normalen Vererbungshierarchie abgebildet werden können. Durch Implementieren des Groesse-Interfaces können sie die Verfügbarkeit der zwei Methoden laenge und hoehe unabhängig von ihrer eigenen Vererbungslinie garantieren. 3. Swing 3.1 Grundlagen 3.1.1 Abstract Windowing Toolkit (AWT) Java wurde von Anfang an auch mit dem Anspruch entwickelt, ein vielseitiges, aber einfach zu bedienendes System für die Gestaltung grafischer Oberflächen zur Verfügung zu stellen. Diese Grafikbibliothek steht unter dem Namen Abstract Windowing Toolkit (AWT) zur Verfügung. Die Fähigkeiten des AWT lassen sich grob in vier Gruppen unterteilen: ! Grafische Primitivoperationen zum Zeichnen von Linien oder Füllen von Flächen und zur Ausgabe von Text ! Methoden zur Steuerung des Programmablaufs auf der Basis von Nachrichten für Tastatur-, Maus- und Fensterereignisse 33 ! Dialogelemente zur Kommunikation mit dem Anwender und Funktionen zum portablen Design von Dialogboxen ! Fortgeschrittenere Grafikfunktionen zur Darstellung und Manipulation von Bitmaps und zur Ausgabe von Sound Da die grafischen Fähigkeiten Bestandteil der Sprache bzw. ihrer Klassenbibliothek sind, können sie als portabel angesehen werden. Unabhängig von der Zielplattform wird ein GUIbasiertes Programm auf allen verwendeten Systemen gleich oder zumindest ähnlich laufen. Die plattformunabhängige graphische Programmierschnittstelle wird durch das Paket java.awt realisiert. In diesem Paket sind Klassen und Schnittstellen zum Arbeiten mit Fenstern, Menüs, Bedienköpfen, usw. zusammengefasst. Die graphische Ausgabe in Fenstern wird durch eine abstrakte Klasse beschrieben, in der wichtige graphische Ausgabefunktionen zu finden sind. Auf diese Weise wird die Plattform-Unabhängigkeit von Java – Anwendungsprogrammen erreicht: AWT: Eine plattformunabhängige API Java Virtual Machine API (Application Program Interface) sind Programmierschnittstellen für GUI’s) Plattformspezifisches API [Quelle: Heinz-Peter Gumm / Manfred Sommer: Einführung in die Informatik] Das Abstract Windowing Toolkit (AWT) von Java enthält verschiedene Fensterklassen, die über eine gemeinsame Vererbungshierarchie miteinander in Verbindung stehen. Oberste Fensterklasse ist Component, aus ihr wird Container abgeleitet. Container ist wiederum die Oberklasse der beiden Klassen Window und Panel. Während Window sich in die Unterklassen Frame und Dialog verzweigt, wird aus Panel die Klasse Applet abgeleitet. Unterhalb von Dialog gibt es noch den Standard-File-Dialog in der Klasse FileDialog. 34 [Quelle: http://developer.java.sun.com] Beispiel-Applet: Ein einfacher Rechner zum Addieren und Subtrahieren: Der Wert im zweiten Textfeld (Eingabe) wird entweder zum Wert des ersten Textfeldes (Ausgabe) addiert oder von diesem subtrahiert. AddSub.java: 35 import java.awt.*; import java.awt.event.*; import java.applet.*; Nachdem die benötigten Klasen importiert wurden, wird die Klasse AddSub, die aus Applet abgeleiten wird, definiert. public class AddSub extends Applet implements ActionListener { private TextField ausgabe; private TextField eingabe; Die Komponenten werden erzeugt. Den beiden Buttons wird jeweils ein ActionListener zugewiesen. Ein Klick auf einen Button löst nun ein Ereignis aus. public void init() { setBackground(Color.lightGray); setLayout(new GridLayout(2, 1)); ausgabe = new TextField("100"); add(ausgabe); Panel p = new Panel(); p.setLayout(new FlowLayout(FlowLayout.CENTER)); eingabe = new TextField("0"); p.add(eingabe); Button add = new Button("Addieren"); add.addActionListener(this); p.add(add); Button sub = new Button("Subtrahieren"); sub.addActionListener(this); p.add(sub); add(p); } Hier werden die Aktionen der Buttons definiert. Wenn Button „Addieren“ angeklickt wird, so wird der Wert des zweiten Textfeldes zum ersten hinzugezählt. Mit dem Button „Subtrahieren“ wird der Wert des zweiten Textfeldes vom ersten abgezogen. public void actionPerformed(ActionEvent event) { String cmd = event.getActionCommand(); int tf1 = Integer.parseInt(ausgabe.getText()); int tf2 = Integer.parseInt(eingabe.getText()); if (cmd.equals("Addieren")) { ausgabe.setText("" + (tf1 + tf2)); } if (cmd.equals("Subtrahieren")) { ausgabe.setText("" + (tf1 - tf2)); 36 } } } Und so sieht der html-Code aus: <HTML> <Head> <Title>AddSub-Applet</Title> </Head> <Body> <H1>AddSub-Applet</H1> <HR> <Applet Code="AddSub.class" Width=300 Height=75> </Applet> <HR> </Body> </HTML> 3.1.2 Vom AWT zum Swing 1. Das Abstract Windowing Toolkit (AWT) des JDK 1.0 Das AWT wurde 1996 mit dem JDK 1.0 eingeführt. Es war nahezu ideal für einfache Web -Animationen aber ungeeignet für komplexere Anwendungen. Außerdem war das AWT noch sehr langsam und fehlerhaft. Das Event-Modell war unzulänglich und die Auswahl an Interaktionsobjekten war sehr gering. Das Look and Feel war noch plattformabhängig. 2. Das Abstract Windowing Toolkit (AWT) des JDK 1.1 Das AWT 1.1 brachte große Verbesserungen im Gegensatz zum AWT 1.0. Es war um einiges schneller und robuster. Das Programmierkonzept wurde stark verbessert: Java Beans und der Event-Subscriber-Mechanismus tauchten hier zum Beispiel zum ersten Mal auf. Leider gab es immer noch zu wenig Interaktionsobjekte. 3. Swing und die Java Foundation Classes (JFC) Swing wurde im März 1998 eingeführt und ist aus einer Zusammenarbeit von Netscape und SUN hervorgegangen. Swing wurde komplett in Java verfasst und ist daher plattformunabhängig. Man spricht von „Lightweight components“ (leichtgewichtige Komponenten). Endlich gab es auch die vielen neuen Features und Verbesserungen, wie 37 zum Beispiel das „Pluggable Look and Feel“. Des Weiteren wurden das KeyboardHandling und das GUI-Rendering stark verbessert. Zu guter Letzt gab es nun auch eine Vielzahl neuer Interaktionsobjekte. 3.1.3 Unterschiede AWT - Swing Zu allererst wäre einmal zu erwähnen, dass Swing auf AWT basiert und noch dessen Event Handling und Layout - Manager verwendet. Jedoch ist Swing um einiges mächtiger. Im Gegensatz zum AWT benutzen Swing-Komponenten nur noch in sehr eingeschränkter Weise plattformspezifische GUI-Ressourcen. Abgesehen von Top-Level-Fenstern, Dialogen und grafischen Primitivoperationen werden alle GUI-Elemente von Swing selbst erzeugt: Zum Beispiel wird ein Swing-Button unter Windows nicht mehr vom Windows-UI-Manager dargestellt, sondern von Swing selbst gezeichnet. Statt jeweils plattformspezifisches Look and Feel anzunehmen, lässt sich mit Swing das LAF dynamisch (auch zur Laufzeit) wechseln. Des Weiteren ist unter Swing auch der Austausch von Daten zwischen den GUI-Elementen per Drag&Drop möglich. Ein bedeutender Unterschied zwischen den AWT- und Swing-Hauptfenstern besteht in ihrer Komponentenstruktur und den sich daraus ergebenden Unterschieden in der Bedienung. Während die Komponenten eines AWT-Fensters direkt auf dem Fenster platziert werden, besitzt ein Swing-Hauptfenster eine einzige Hauptkomponente, die alle anderen Komponenten aufnimmt. 3.1.4 Vorteile von SWING ! Erstens fallen die plattformspezifischen Besonderheiten weg, und der Code zur Implementierung der Dialogelemente vereinfacht sich deutlich. ! Zweitens entfallen auch die Unterschiede in der Bedienung. Der Anwender findet auf allen Betriebssystemen dasselbe Aussehen und dieselbe Bedienung vor. ! Drittens ist Swing nicht mehr darauf angewiesen, Features auf der Basis des kleinsten gemeinsamen Nenners aller unterstützten Plattformen zu realisieren. Komplexe Dialogelemente wie Bäume, Tabellen oder Registerkarten können 38 plattformunabhängig realisiert werden und stehen nach der Implementierung ohne Portierungsaufwand auf allen Systemen zur Verfügung. Tatsächlich stellt Swing eine sehr viel umfassendere und anspruchsvollere Menge an Dialogelementen als das AWT zur Verfügung. 3.1.5 Abhängigkeit Swing – AWT AWT (Abstract Windowing Toolkit) ist der Teil von Java zum Erstellen von User Interfaces und Zeichnen von Grafiken und Bilder. Es ist ein Satz von Klassen, der zur Verfügung stellen soll, was ein Entwickler benötigt, um ein grafisches Interface für Java Applets und Anwendungen zu erzeugen. Die meisten AWT Komponenten sind aus der java.awt.Component Klasse hergeleitet. Die Java Foundation Classes (JFC) bestehen aus fünf Hauptteilen: AWT, Swing, Accessibility, Java 2D und Drag and Drop. Java 2D wurde in AWT integriert. Swing ist auf AWT aufgebaut. Diese fünf Teile von JFC sind also mit Sicherheit nicht unabhängig von einander und von Swing wird angenommen, dass es in zukünftigen Versionen von Java immer mehr mit AWT verschmelzen wird. Drag and Drop wird voraussichtlich in naher Zukunft auch in Swing und AWT integriert werden. AWT ist das Kerngehäuse von JFC und ist somit eine der wichtigsten Klassen in Java 2. Swing ist ein großer Satz von Komponenten beginnend bei sehr einfachen, beispielsweise Labels, bis zu sehr komplexen Komponenten, wie zum Beispiel Tabellen und Trees. Nahezu alle Swing Komponenten sind von JComponent hergeleitet, welche die AWT Container Klasse erweitert. Folglich ist Swing nahezu ein Ersatz für AWT. Swing basiert auf AWT und nutzt in der Regel noch dessen Event-Handling und Layout-Manager. 3.1.6 Eigenschaften von Swing Im Gegensatz zum AWT benutzen Swing-Komponenten nur noch in sehr eingeschränkter Weise plattformspezifische GUI-Ressourcen. Abgesehen von wenigen Ausnahmen (TopLevel-Fenstern, Dialogen und grafischen Primitivoperationen) werden alle GUI-Elemente von Swing selbst erzeugt. 39 Eine der auf den ersten Blick spektakulärsten Eigenschaften von Swing ist die Möglichkeit, das Look-and-Feel (also das Aussehen und die Bedienung einer Anwendung) zur Laufzeit umzuschalten. Dieses als Pluggable Look-and-Feel bezeichnete Feature ermöglicht es beispielsweise einem Windows-Anwender, zwischen drei unterschiedlichen Look-and-Feels zu wählen: Swing (Metal), Motif und Windows. 3.1.7 Swing – Package Überblick javax.swing Das allgemeinste Swing - Package besteht vor allem aus Komponenten, Adaptern, Default Komponenten, default component models, und Interfaces für alle delegates und models. javax.swing.border Das Border - Package bestimmt Border Interface und Klassen, welche die einzelnen Rahmenarten definieren. javax.swing.colorchooser Das Colorchooser - Package beinhaltet Unterstüzungsklassen für das color chooser component. javax.swing.event Das Event - Package steht für die Swing spezifischen event types und listeners. Zusätzlich zu den java.awt.event types können Swing Komponenten ihre eigenen event types generieren. javax.swing.filechooser Das Filechooser - Package beinhaltet Unterstützungsklassen für die file chooser Komponente. 40 javax.swing.plaf.* Das „Pluggable Look-and-Feel” (PLAF) - Package beinhaltet die User Interface (UI) Klassen, welche für das Erscheinungsbild von Swing Komponenten zuständig sind. javax.swing.table Das Table - Package beinhaltet Unterstützungsinterfaces und -klassen der Swing Tabellenkomponente. javax.swing.text Das Text - Package beinhaltet Unterstützungsklassen für das Swing document framework. javax.swing.text.html.* Das Text.html - Package beinhaltet Unterstützungsklassen für einen HTML - Renderer und - Parser. javax.swing.text.rtf Das Text.rtf - Package beinhaltet Unterstützungsklassen für ienen grundlegenden Rich Text Format (RTF) Renderer. javax.swing.tree Das Tree - Package beinhaltet Interfaces und Klassen, die die Swing Tree Komponente unterstützen. javax.swing.undo Das Undo - Package stellt Unterstützungsklassen zum Rückgängig/Wiederherstellen - Fähigkeiten in GUI zur Verfügung. durchführen der 41 3.2 Container Jedes Programm, das Swing Komponenten verwendet, hat zumindest einen Top-level Container. Dieser Top-level Container ist die Wurzel der Hierarchie, die alle innerhalb des Top-level Containers auftauchenden Swing Komponenten beinhaltet. Container ist eine abstrakte Klasse. Sie ist dafür zuständig, innerhalb einer Komponente andere Komponenten aufzunehmen. Container stellt Methoden zur Verfügung, um Komponenten hinzuzufügen oder sie zu entfernen, und realisiert in Zusammenarbeit mit den LayoutManager-Klassen die Positionierung und Anordnung der Komponenten. 3.2.1 JFrame Die Klasse JFrame ist die wichtigste Hauptfensterklasse in Swing. Sie ist aus java.awt.Frame abgeleitet und stellt ein Hauptfenster mit Rahmen, Systemmenü und Standardschaltflächen zur Verfügung. Die Klasse JFrame stellt 2 Konstruktoren zur Verfügung: Einen zum Erzeugen von Frames ohne Titel und einen weiteren zum Erzeugen von Frames mit Titel. 42 1.) public JFrame() JFrame frame = new JFrame(); 2.) public JFrame(String title) JFrame frame = new JFrmae („Title Bar“) Darüber hinaus gibt es noch 2 Konstruktoren zum Erzeugen von Frames, die spezielle graphische Eigenschaften besitzen. 3.) public JFrame (GraphicsConfiguration config) GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice gsd[] = ge.getScreenDevices() ; GraphicsConfiguration gc[] = gsd[0].getConfiguration() ; JFrame frame = new JFrame(gc[0]) ; Man könnte natürlich hier ohne weiteres auch eine Titelleiste einfügen. Wenn man Komponenten zu einem JFrame hinzufügen möchte, muss man die Komponenten zu JRootPane (bzw. zur ContentPane) hinzufügen. Wenn man Komponenten direkt zu JFrame hinzufügt, endet dies mit einem Runtime Error. ein Top-level Container 43 [Quelle: http:// java.sun.com] 3.2.2 JRootPane: Die Container JFrame, JWindow, JDialog, JApplet und JInternalFrame sind in Swing auf die RootPane angewiesen. Anstatt Komponenten direkt zum Container hinzuzufügen, fügt man sie einem Teil der RootPane hinzu. Die RootPane erledigt dann alles Weitere intern. Während die Komponenten eines AWT-Fensters direkt auf dem Fenster platziert werden, besitzt ein Swing-Hauptfenster eine einzige Hauptkomponente, die alle anderen Komponenten aufnimmt. Diese Hauptkomponente wird als RootPane bezeichnet und ist vom Typ JRootPane. Sie übernimmt die Rolle einer Art Verwaltungsinstanz für alle anderen Komponenten des Hauptfensters. Eine RootPane enthält folgende Komponenten: ! eine aus Container abgeleitete GlassPane und ! eine aus JLayeredPane abgeleitete LayeredPane Die LayeredPane enthält ihrerseits zwei Unterkomponenten: ! eine aus Container abgeleitete ContentPane und ! eine aus JMenuBar abgeleitete Menüleiste 44 Diese Komponenten stellt sie für JFrame und alle anderen Top-level Container zur Verfügung. [Quelle: Guido Krüger: GoTo Java 2] [Quelle: http:// java.sun.com] UML Diagramm von JRootPane: 45 JComponent JRootPane.RootLayout Component JRootPane JMenuBar JLayeredPane Container [Quelle: John Zukovski: Definitive Guide to Swing for Java 2] Aber in der Regel muss man nicht so genau über die RootPane Bescheid wissen, wenn man mit Swing Komponenten arbeitet. 3.2.3 JWindow JWindow ist ebenfalls eine Hauptfensterklasse. Sie dient dazu, ein rahmenloses Fenster zu erzeugen, das an beliebiger Stelle und in beliebiger Größe auf dem Bildschirm platziert werden kann. JWindow besitzt folgende drei Konstruktoren: 1.) public JWindow() 46 JWindow window = new JWindow(); 2.) public JWindow(Frame owner) JWindow window = new JWindow(aFrame); 3.) public JWindow(Window owner) JWindow window = new JWindow(anotherWindow); 3.2.4 JDialog In den meisten Fällen besitzt eine Anwendung auch Dialogfenster. Diese werden oft nur vorübergehend aufgerufen, um eine temporäre Kommunikation zwischen Anwender und Programm herzustellen. Während ihrer Ausführung wird der Programmfluss angehalten. Im Unterschied zu Hauptfenstern besitzen Dialogfenster kein Menü und nur eingeschränkte Systemfunktionen. Zudem ist ihre Größe oft nicht veränderbar. Dialogfenster besitzen denselben strukturellen Aufbau wie JFrame und JWindow und implementieren ebenfalls das Interface RootPaneContainer. Auch hier erfolgt also das Hinzufügen und Anordnen von Komponenten nicht auf dem Fenster selbst, sondern auf seiner ContentPane. Einige Konstruktoren von JDialog: 1.) public JDialog() JDialog dialog = new JDialog(); 2.) public JDialog (Frame owner) JDialog = new JDialog(aFrame); 47 3.) public JDialog (Frame owner, boolean modal) JDialog = new JDialog(aFrame, false); 4.) public JDialog (Frame owner, String windowTitle) JDialog = new JDialog(aFrame, “Hello”); 5.) public JDialog (Frame owner, String title, boolean modal) JDialog = new JDialog(aFrame, “Hello“, true); Als owner sollte der Aufrufer dabei das Fenster übergeben, zu dem der Dialog logisch gehört. Alle Konstruktoren gibt es auch in einer Form, bei der der owner vom Typ Dialog ist, zum Beispiel: public JDialog (Dialog owner) JDialog = new JDialog(anotherDialog); Die übrigen Parameter geben den Titel des Dialogs an und legen fest, ob er modal oder nichtmodal sein soll. Bei einem modalen Dialog wird der Aufruf von show (bzw. setVisible(true)) erst dann beendet, wenn der Dialog geschlossen wurde. Bei einem nicht- modalen Dialog fährt das Programm dagegen unmittelbar mit der nächsten Anweisung hinter show fort. 3.2.5 JComponent Viele der Swing-Komponenten sind direkt oder indirekt aus der Klasse JComponent abgeleitet. Sie stellt eine Reihe allgemeiner Hilfsmittel zur Verfügung, die für daraus abgeleitete Komponentenklassen nützlich sind. Als Ableitung von java.awt.Container und somit auch von java.awt.Component besitzt JComponent bereits einen Großteil der Funktionalität von AWT-Komponenten. Insbesondere bietet sie als Container die 48 Möglichkeit, andere Komponenten aufzunehmen, und sie kann einen Layout-Manager besitzen, der für die Größe und Anordnung der enthaltenen Komponenten zuständig ist. 3.2.6 Weitere Container ! JOptionPane ! JApplet ! JInternalFrame 3.3 Komponenten Die abstrakte Klasse JComponent wird - mit Ausnahme der Hauptfenster - als Basisklasse für praktisch alle Swing-Komponenten verwendet. JComponent ist direkt aus Container abgeleitet und besitzt daher alle Eigenschaften der Klassen Component und Container. Die folgenden Komponenten Hierarchien zeigen die Vielfalt der Komponenten in Swing: 49 [Quelle: http://developer.java.sun.com] Die Komponenten in der ersten Abbildung sind den Komponenten in AWT ähnlich. Insgesamt gibt es mehr als doppelt so viele Komponenten in Swing als in AWT. Hier sind die neueren und erweiterten Komponenten abgebildet: 50 [Quelle: http://developer.java.sun.com] 3.3.1 Panels 51 JPanel ist die Basisklasse für GUI-Container in Swing, die nicht Hauptfenster sind. Sie ist direkt aus JComponent abgeleitet. JPanel dient dazu, eine Reihe von Dialogelementen unter Kontrolle eines eigenen Layoutmanagers anzuordnen. Einem JPanel ist standardmäßig ein FlowLayout als Layoutmanager zugeordnet. Anders als bei den Hauptfenstern gibt es hier keine ContentPane, sondern die Dialogelemente und der Layoutmanager werden dem Panel direkt zugewiesen. public JPanel() public JPanel(LayoutManager layout) 3.3.2 Label- und Textfelder Ein JLabel ist ein Dialogelement zur Anzeige einer Beschriftung innerhalb eines GUIContainers. Es kann einen Text und/oder ein Icon enthalten, die in beliebiger Anordnung dargestellt werden können. Auf Benutzereingaben reagiert ein JLabel nicht. public JLabel(String text) public JLabel(Icon image) public JLabel(String text, Icon icon, int horizontalAlignment) Die Klasse JTextField stellt ein einzeiliges Textfeld zur Eingabe von Daten dar. Ein Großteil der Fähigkeiten von JTextField ist in der Basisklasse JTextComponent des Pakets javax.swing.text implementiert. Die wichtigsten Konstruktoren von JTextField sind: public JTextField(int columns) public JTextField(String text) public JTextField(String text, int columns) Der erste von ihnen erzeugt ein leeres Textfeld mit der angegebenen Anzahl Spalten, der zweite ein Textfeld mit dem angegebenen Text. Beim dritten Konstruktor können sowohl Spaltenzahl als auch Text vorgegeben werden. 52 3.3.3 Buttons Swing-Buttons sind Instanzen der Klasse JButton und dienen dazu, Schaltflächen zu erzeugen. Ein Button kann wahlweise mit Beschriftung, mit Icon oder mit beidem instanziert werden: public JButton(String text) public JButton(Icon icon) public JButton(String text, Icon icon) 3.3.4 Listen und Comboboxen Die Klasse JList dient dazu, Listen von Werten darzustellen, aus denen der Anwender einen oder mehrere Einträge auswählen kann. public JList() public JList(Object[] listData) public JList(Vector listData) public JList(ListModel dataModel) Der parameterlose Konstruktor erzeugt eine leere Liste. Wird ein Array oder Vector übergeben, erzeugt JList aus dessen Daten ein Listenmodell und benutzt es zur Darstellung. Um den Inhalt der Liste zu definieren, kann auch direkt eine Instanz der Klasse ListModel übergeben werden. Eine JList wird meist in eine JScrollPane eingebettet, bevor sie zu einem GUI-Container hinzugefügt wird um die Fähigkeit des Scrollens zu gewährleisten. 53 Eine JComboBox stellt eine Kombination aus Textfeld und Liste dar. Die Liste ist normalerweise unsichtbar und wird vom Anwender nur dann geöffnet, wenn er einen Wert daraus auswählen will. Sie erlaubt grundsätzlich nur einfache Selektion. public JComboBox(Object[] items) public JComboBox(Vector items) public JComboBox(ComboBoxModel aModel) 3.3.5 Schieberegler JScrollBar dient dazu, mit Hilfe eines Schiebereglers einen Wert kontinuierlich innerhalb vorgegebener Grenzen einzustellen. public JScrollBar( int orientation, int value, int extent, int min, int max ) Mit orientation wird die Ausrichtung des Schiebereglers festgelegt. Sie kann entweder horizontal oder vertikal sein. min gibt den kleinsten, max den größten möglichen Wert an. Mit 54 extent wird die Ausdehnung des Schiebers festgelegt. Sie muss mindestens eins, kann aber auch größer sein. value ist der Anfangswert des Schiebers. JProgressBar stellt eine Fortschrittsanzeige dar, wie sie auch das Betriebssystem oder ein Installationsprogramm bei längeren Kopiervorgängen anzeigt. public JProgressBar(int orient) public JProgressBar(int min, int max) public JProgressBar(int orient, int min, int max) Der Parameter orient gibt die Orientierung der Fortschrittsanzeige an, sie kann wahlweise horizontal oder vertikal sein. Standardmäßig erzeugt Swing eine horizontale Darstellung. min und max geben die untere und obere Grenze des Wertebereichs an. Voreinstellung ist 0 bzw. 100. 3.3.6 Menüs In Swing können alle Hauptfenster mit Ausnahme von JWindow eine Menüleiste haben. Dabei handelt es sich um eine Instanz der Klasse JMenuBar, die dem Hauptfenster durch Aufruf von addJMenuBar hinzugefügt wird. public JMenuBar() public JMenu add(JMenu c) Die einzelnen Menüs einer Menüleiste sind Instanzen der Klasse JMenu, die aus JMenuItem abgeleitet ist. Der Konstruktor erzeugt ein neues Menü mit dem angegebenen Namen. Mit add werden Menüeinträge hinzugefügt. Meist sind das Instanzen der Klasse JMenuItem, die auf vielfältige Weise konfiguriert werden können. public JMenu(String s) public JMenuItem add(String s) public JMenuItem add(JMenuItem menuItem) 55 Die Klasse JMenuItem repräsentiert Menüeinträge, also Elemente, die sich in einem Menü befinden. Da JMenu aus JMenuItem abgeleitet ist, kann ein Menü wiederum Menüs als Einträge enthalten. Auf diese Weise lassen sich Menüs schachteln. public JMenuItem(String text) public JMenuItem(String text, Icon icon) public JMenuItem(String text, int mnemonic) 3.3.7 Weitere Komponenten ! JTable ! JTree 56 3.4 Look and Feel Jede Komponente in AWT besitzt eine „schwergewichtige“ peer Klasse, die zwischen einer JAVA Komponente und einem Betriebssystem Hilfsmittel „vermittelt“. Zum Beispiel sieht eine java.awt.Button Komponente unter Windows 95 nach einem Windows 95 Button aus, unter dem Solaris Betriebssystem aber wie ein Motif Button. Jedoch hat der Entwickler keinen Einfluss auf diesen Prozess. Swing Komponenten basieren auf „leichtgewichtigen“ Komponenten. Das heißt, sie sind nicht mehr vom Betriebssystem abhängig. Im Gegensatz zu AWT - Komponenten können Swing – Komponenten verschieden aussehen auf derselben Plattform. SWING Look and Feel AWT Look and Feel Component JComponent (MVC Model) Peer (native) MVC View MVC Controller ComponentUI (Delegate) [Quelle: http://developer.java.sun.com] Platform Widged (native) 57 Eine der auf den ersten Blick spektakulärsten Eigenschaften von Swing ist die Möglichkeit, das Look-and-Feel, also das Aussehen und die Bedienung einer Anwendung, zur Laufzeit umzuschalten. Dieses als Pluggable Look-and-Feel bezeichnete Feature ermöglicht es einem Anwender, zwischen drei unterschiedlichen Look-and-Feels zu wählen: ! Swing ! Motif ! Windows Alle Swing-Komponenten sind so konstruiert, dass es möglich ist, das Look-and-Feel einer Anwendung zur Laufzeit umzuschalten. Das Programm selbst muss praktisch keinen zusätzlichen Aufwand treiben, denn das Umschalten wird nach einem einzigen Methodenaufruf von einem User-Interface-Manager erledigt, der alle nötigen Maßnahmen koordiniert ausführt. Um eine Anwendung im Metal – Look darzustellen, muss man folgenden Code verwenden. try { UIManager.setLookAndFeel ( "javax.swing.plaf.metal.MetalLookAndFeel"); } catch (java.lang.ClassNotFoundException e) { } Das Metal Look and Feel ist Standard in Swing Anwedungen. Es ist ein Versuch ein gemeinsames Aussehen gegenüber verschiedenen Computer Umgebungen zu erzeugen. Der folgende Code würde das plattformspezifische Look and Feel verwenden: try { UIManager.setLookAndFeel ( UIManager.getCrossPlatformLookAndFeelClassName()); } catch (java.lang.ClassNotFoundException e) { } Metal LAF: Motif LAF: Windows LAF: 58 3.5 Model-View-Controller Neben den äußerlichen Qualitäten wurde auch die Architektur des Gesamtsystems verbessert. Das Anwenden einer Technologie, genannt Model/View/Controller (MVC) – Prinzip, gibt dem Programmierer die Kontrolle über das Aussehen der Hilfsmittel, wie sie auf Inputs reagieren und, für einige komplexerer Hilfsmittel, wie Daten dargestellt werden. MVC ist ein Design Muster, das oft zum Erstellen von User Interfaces (UI) verwendet wird. Anstatt den gesamten Code in eine einzelne Klasse zu packen, unterscheidet man beim MVCKonzept drei unterschiedliche Bestandteile eines grafischen Elements: ! Das Modell enthält die Daten des Dialogelements und speichert seinen Zustand. ! View ist für die grafische Darstellung der Komponente verantwortlich. ! Der Controller wirkt als Verbindungsglied zwischen beiden. Er empfängt Tastaturund Mausereignisse und stößt die erforderlichen Maßnahmen zur Änderung von Model und View an. Das Modell enthält praktisch die gesamte Verarbeitungslogik der Komponente. Ein wichtiger Aspekt ist dabei, dass ein Model mehrere Views gleichzeitig haben kann. Damit Veränderungen des Modells in allen Views sichtbar werden, wird ein Benachrichtigungsmechanismus implementiert, mit dem das Modell die zugeordneten Views über Änderungen informiert. Bei den Swing-Dialogelementen wird eine vereinfachte Variante von MVC verwendet, die auch als Model-Delegate-Prinzip bezeichnet wird. Hierbei wird die Funktionalität von View und Controller zusammengefasst. Dadurch wird einerseits die Komplexität reduziert und andererseits die unhandliche Trennung zwischen View und Controller aufgehoben. Es kann allerdings sein, dass ein Dialogelement mehr als ein Model besitzt. So haben beispielsweise Listen und Tabellen neben ihrem eigentlichen Datenmodell ein weiteres, das nur für die Selektion von Datenelementen zuständig ist. 59 3.6 Layout - Manager In vielen grafischen Oberflächen wird die Anordnung der Elemente eines Dialoges durch Angabe absoluter Koordinaten vorgenommen. Da Java Programme natürlich auf vielen unterschiedlichen Plattformen laufen sollen, ist ein Layoutmanager für die Anordnung der Elemente verantwortlich. Ein Layoutmanager wird mit der Methode setLayout einem Fenster zugeordnet. Mit add werden dann die Elemente übergeben und angeordnet. Die tatsächliche Anordnung der Komponenten auf dem Bildschirm bestimmt in der Regel die Reihenfolge der Aufrufe der add-Methode des Fensters. Wenn nicht - wie es z.B. beim BorderLayout möglich ist - zusätzliche Positionierungsinformationen an das Fenster übergeben werden, ordnet der jeweilige Layoutmanager die Komponenten in der Reihenfolge ihres Eintreffens an. ! FlowLayout: Die Dialogelemente werden nebeneinander in einer Zeile angeordnet. Ist in der ersten Zeile kein Platz mehr vorhanden, wird mit der nächsten fortgefahren. setLayout(new FlowLayout(FlowLayout.LEFT)); add(new Button("Button 1")); add(new Button("Button 2")); add(new Button("Button 3")); add(new Button("Button 4")); add(new Button("Button 5")); 60 ! GridLayout: Die Dialogelemente werden in einem rechteckigen Gitter angeordnet. Zeilen- und Spaltenzahl wird beim Erstellen des Layoutmanagers angegeben. setLayout(new GridLayout(4,2)); add(new Button("Button 1")); add(new Button("Button 2")); add(new Button("Button 3")); add(new Button("Button 4")); add(new Button("Button 5")); add(new Button("Button 6")); add(new Button("Button 7")); ! BorderLayout: Die Dialogelemente werden auf die vier Randbereiche und den Mittelbereich des Fensters verteilt. setLayout(new BorderLayout()); add("North", new Button("North")); add("South", new Button("South")); add("West", new Button("West")); add("East", new Button("East")); add("Center", new Button("Center")); 61 ! GridBagLayout: GridBagLayout erweitert die Fähigkeiten von GridLayout und macht es möglich, sehr komplexe Layouts zu erzeugen. Wenn die Grundausprägungen der jeweiligen Layoutmanager nicht ausreichen, besteht die Möglichkeit Layoutmanager zu schachteln. Auf diese Weise kann auch ohne Vorgabe fester Koordinaten fast jede gewünschte Komponentenanordnung realisiert werden. Sollte auch diese Variante nicht genau genug sein, so bietet sich schließlich durch Verwendung eines Null-Layouts die Möglichkeit an, Komponenten durch Vorgabe fester Koordinaten zu platzieren. 62 3.7 Event Handling Jedes Mal, wenn ein Anwender etwas schreibt oder einen Mausbutton drückt, ereignet sich ein Event. Jedes Objekt kann von diesem Event benachrichtigt werden. Alles was es tun hat, ist das passendes Interface durchzuführen und sich als EventListener für den passenden Event Source zu registrieren. Swing Komponenten sind in der Lage viele EventListener zu generieren. Hier einige Beispiele: ActionListener WindowListener MouseListener MouseMotionListener ComponentListener FocusListener ListSelectionListener Anwender klickt einen Button, drückt Return in einem Textfeld oder wählt einen Menüpunkt aus. Anwender schließt Frame (Hauptfenster) Anwender drückt Mausbutton während sich der Cursor über einer Komponente befindet. Anwender bewegt die Maus über eine Komponente Komponente wird sichtbar Komponente bekommt Tastaturfokus Tabellen- oder Listenauswahl wechselt Jedes Event wird von einem Objekt vertreten, das Informationen über das Event enthält und den Event Source identifiziert. Event Sources sind in den meisten Fällen Komponenten. Um einen EventListener einzubauen benötigt man einen 3-teiligen Code: 1.) Deklaration der Event - Handler - Klasse: public class Klasse implements ActionListener { 2.) Registriert eine Instanz aus der Event Handler Klasse als einen Listener für eine oder mehrere Komponenten: eineKomponente.addActionListener(InstanzVonKlasse); 63 3.) Führt die Methoden im Listener Interface aus: public void actionPerformed(ActionEvent e) { ...//Code, der auf die Aktion reagiert... } 64 4. Beispielprogramme 4.1 Millionenshow Ich bin mir sicher jedem ist das TV-Quiz „Millionenshow“ ein Begriff. Und genau dieses Frage-Antwort-Spiel wird hier versucht, in vereinfachter Weise nachzuahmen. Der Ablauf erweist sich als recht einfach: Aus einer Textdatei, die die Fragen und Antworten beinhaltet, werden diese ausgelesen. Auf der Benutzeroberfläche erscheint nun die Frage mit den vier Antwortmöglichkeiten. Nachdem eine Antwort ausgewählt wurde, wird diese mit der korrekten Antwort verglichen. Stimmen sie überein, so wird der Text „Richtig“ ausgegeben, andernfalls „Falsch“. Nachdem man eine Frage beantwortet hat, besteht die Möglichkeit eine neue Frage anzeigen zu lassen. 65 Darstellung der Klassen in UML: main.java main.java wird von JBuilder automatisch erzeugt und dient zur Einstellung und Ausrichtung des Fensters. package millionenshow; import javax.swing.UIManager; import java.awt.*; public class main { boolean packFrame = false; /**Construct the application*/ public main() { MainScreen frame = new MainScreen(); //Validate frames that have preset sizes //Pack frames that have useful preferred size info, e.g. from their layout if (packFrame) { frame.pack(); } else { frame.validate(); } //Center the window Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); Dimension frameSize = frame.getSize(); if (frameSize.height > screenSize.height) { frameSize.height = screenSize.height; } if (frameSize.width > screenSize.width) { frameSize.width = screenSize.width; 66 } frame.setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height) / 2); frame.setVisible(true); } /**Main method*/ public static void main(String[] args) { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch(Exception e) { e.printStackTrace(); } new main(); } } MainScreen.java Dies ist das Hauptfenster der Anwendung und gleichzeitig der Teil den der Benutzer sieht. package millionenshow; Die benötigten Klassen werden importiert. import java.lang.Math; import java.util.Random; import java.awt.*; import java.awt.event.*; import javax.swing.*; import com.borland.jbcl.layout.*; import java.lang.InterruptedException; import java.lang.Thread; Die Klasse MainScreen (aus JFrame abgeleitet) wird definiert. Des Weiteren werden in diesem Teil die Komponenten erzeugt und die Variablen deklariert. public class MainScreen extends JFrame { JPanel contentPane; XYLayout xYLayout1 = new XYLayout(); JButton jButton1 = new JButton(); JTextArea frage = new JTextArea(); JButton antwort1 = new JButton(); JButton antwort3 = new JButton(); JButton antwort2 = new JButton(); JButton antwort4 = new JButton(); private FragenContainer fc = new FragenContainer(); private int activeQuestion = 1; 67 private Random myRandom = new Random(System.currentTimeMillis()); JButton newQuestion = new JButton(); Der Frame wird aufgebaut. /**Construct the frame*/ public MainScreen() { enableEvents(AWTEvent.WINDOW_EVENT_MASK); try { jbInit(); } catch(Exception e) { e.printStackTrace(); } } Den Komponenten werden Eigenschaften und Event-Handler zugewiesen. Das Panel bekommt ein Layout. /**Component initialization*/ private void jbInit() throws Exception { contentPane = (JPanel) this.getContentPane(); jButton1.setText("About"); jButton1.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(ActionEvent e) { jButton1_actionPerformed(e); } }); jButton1.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseReleased(MouseEvent e) { jButton1_mouseReleased(e); } }); contentPane.setLayout(xYLayout1); this.setSize(new Dimension(451, 300)); this.setTitle("MillionenShow"); this.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseReleased(MouseEvent e) { this_mouseReleased(e); } }); frage.setText("jTextArea1"); antwort1.setText("jButton2"); antwort3.setText("jButton2"); antwort2.setText("jButton2"); antwort4.setText("jButton2"); newQuestion.setText("Neue Frage"); newQuestion.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseReleased(MouseEvent e) { newQuestion_mouseReleased(e); } }); 68 Die Komponenten werden am Panel ausgerichtet. contentPane.add(jButton1, new XYConstraints(131, 24, 130, 32)); contentPane.add(frage, new XYConstraints(24, 78, 347, 55)); contentPane.add(antwort1, new XYConstraints(27, 151, 133, 34)); contentPane.add(antwort3, new XYConstraints(213, 151, 157, 32)); contentPane.add(antwort2, new XYConstraints(25, 219, 138, 31)); contentPane.add(antwort4, new XYConstraints(212, 219, 157, 32)); contentPane.add(newQuestion, new XYConstraints(309, 28, 116, 29)); Wenn die Maustaste nach anklicken der einzelnen Antwortmöglichkeiten wieder losgelassen wird, wird die jeweilige Methode aufgerufen. this.initQuestions(); antwort1.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseReleased(MouseEvent e) { antwort1_mouseReleased(e); } }); antwort2.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseReleased(MouseEvent e) { antwort2_mouseReleased(e); } }); antwort3.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseReleased(MouseEvent e) { antwort3_mouseReleased(e); } }); } Beim Schließen des Fensters wird automatisch die gesamte Anwendung beendet. /**Overridden so we can exit when window is closed*/ protected void processWindowEvent(WindowEvent e) { super.processWindowEvent(e); if (e.getID() == WindowEvent.WINDOW_CLOSING) { System.exit(0); } } Diese Methode ist für die Textübergabe von Frage und Antworten zuständig. protected void initQuestions() { this.activeQuestion = (Math.abs(this.myRandom.nextInt()) % this.fc.getAnzahl())+1; this.frage.setText(this.fc.getFrage(activeQuestion)); this.antwort1.setText(this.fc.getAntwort(activeQuestion,1)); this.antwort2.setText(this.fc.getAntwort(activeQuestion,2)); this.antwort3.setText(this.fc.getAntwort(activeQuestion,3)); this.antwort4.setText(this.fc.getAntwort(activeQuestion,4)); } 69 Die gegebene Antwort wird auf ihre Richtigkeit überprüft. Die Methode erfährt von der unten folgenden Methode, welche Antwort zu überprüfen ist. protected void checkAnswere(int which) { int c = this.fc.getKorrekt(activeQuestion); if (c==which) this.frage.setText("JUHU"); else this.frage.setText("Ätsch"); this.repaint(); activeQuestion=0; } Wenn Button1 angeklickt wird, öffnet dich MainScreenAboutBox. void jButton1_mouseReleased(MouseEvent e) { MainScreen_AboutBox m = new MainScreen_AboutBox(this); m.show(); } void jButton1_actionPerformed(ActionEvent e) { } Hier sind nun die schon zuvor besprochenen Methoden. Wenn Anwort1 gegeben wurde, wird der Methode „checkAnswere“ der Wert „1“ zurückgeliefert, wenn Antwort2 gegeben wurde, der Wert „2“, usw. void antwort1_mouseReleased(MouseEvent e) { this.checkAnswere(1); } void antwort2_mouseReleased(MouseEvent e) { this.checkAnswere(2); } void antwort3_mouseReleased(MouseEvent e) { this.checkAnswere(3); } void this_mouseReleased(MouseEvent e) { this.checkAnswere(4); } Nach Anklicken des newQuestion Buttons wird die Methode initQuestions wieder aufgerufen und der Frame neu aufgebaut. void newQuestion_mouseReleased(MouseEvent e) { this.initQuestions(); this.repaint(); } } 70 MainScreen_AboutBox.java MainScreenAboutBox ist das Info-Fenster der Anwendung. Dieses beinhaltet Version und Copyright der Anwendung. package millionenshow; import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.border.*; Die Klasse MainScreenAboutBox wird definiert und ein ActionListener wird implementiert. public class MainScreen_AboutBox extends JDialog implements ActionListener { JPanel panel1 = new JPanel(); JPanel panel2 = new JPanel(); JPanel insetsPanel1 = new JPanel(); JPanel insetsPanel2 = new JPanel(); JPanel insetsPanel3 = new JPanel(); JButton button1 = new JButton(); JLabel imageLabel = new JLabel(); JLabel label1 = new JLabel(); JLabel label2 = new JLabel(); JLabel label3 = new JLabel(); JLabel label4 = new JLabel(); BorderLayout borderLayout1 = new BorderLayout(); BorderLayout borderLayout2 = new BorderLayout(); FlowLayout flowLayout1 = new FlowLayout(); GridLayout gridLayout1 = new GridLayout(); String product = ""; String version = "1.0"; String copyright = "Copyright (c) 2001"; String comments = ""; public MainScreen_AboutBox(Frame parent) { super(parent); enableEvents(AWTEvent.WINDOW_EVENT_MASK); try { jbInit(); } catch(Exception e) { e.printStackTrace(); } pack(); } /**Component initialization*/ private void jbInit() throws Exception { this.setTitle("About"); setResizable(false); 71 panel1.setLayout(borderLayout1); panel2.setLayout(borderLayout2); insetsPanel1.setLayout(flowLayout1); insetsPanel2.setLayout(flowLayout1); insetsPanel2.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); gridLayout1.setRows(4); gridLayout1.setColumns(1); label1.setText("created by chef"); label2.setText(version); label3.setText(copyright); label4.setText(comments); insetsPanel3.setLayout(gridLayout1); insetsPanel3.setBorder(BorderFactory.createEmptyBorder(10, 60, 10, 10)); button1.setText("Ok"); button1.addActionListener(this); insetsPanel2.add(imageLabel, null); panel2.add(insetsPanel2, BorderLayout.WEST); this.getContentPane().add(panel1, null); insetsPanel3.add(label1, null); insetsPanel3.add(label2, null); insetsPanel3.add(label3, null); insetsPanel3.add(label4, null); panel2.add(insetsPanel3, BorderLayout.CENTER); insetsPanel1.add(button1, null); panel1.add(insetsPanel1, BorderLayout.SOUTH); panel1.add(panel2, BorderLayout.NORTH); } /**Overridden so we can exit when window is closed*/ protected void processWindowEvent(WindowEvent e) { if (e.getID() == WindowEvent.WINDOW_CLOSING) { cancel(); } super.processWindowEvent(e); } /**Close the dialog*/ void cancel() { dispose(); } /**Close the dialog on a button event*/ public void actionPerformed(ActionEvent e) { if (e.getSource() == button1) { cancel(); } } } 72 FragenContainer.java FragenContainer beinhaltet, wie der Name schon sagt, die gesamten Antworten und Fragen, die aus einer Textdatei bezogen werden. package millionenshow; import java.util.Hashtable; import java.io.FileInputStream; import java.io.File; import java.io.FileReader; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; import java.util.StringTokenizer; In der Klasse FragenContainer wird eine Hashtable erzeugt. public class FragenContainer { private Hashtable con = new Hashtable(); Methode, die die Fragen ausliest. public String getAntwort(int frage,int antwort) { if (antwort==1) return ((Frage)con.get("" + frage)).getAntwort1(); else if (antwort==2) return ((Frage)con.get("" + frage)).getAntwort2(); else if (antwort==3) return ((Frage)con.get("" + frage)).getAntwort3(); else if (antwort==4) return ((Frage)con.get("" + frage)).getAntwort4(); else return ""; } Methode, die die korrekte Antwort ausliest. public int getKorrekt(int frage) { return ((Frage)con.get("" + frage)).getKorrekt(); } Methode, die die Frage ausliest. public String getFrage(int frage) { return ((Frage)con.get("" + frage)).getFrage(); } Die Größe der Hashtable wird ermittelt. public int getAnzahl () { return con.size(); } 73 Aus der Textdatei werden die Informationen herausgelesen und nach Frage, Antworten und der korrekten Antwort gesucht. public FragenContainer() { BufferedReader fs=null; try { Auf die Textdatei wird zugegriffen. fs = new BufferedReader(new InputStreamReader(new FileInputStream("fragen.txt"))); String line; int j = 1; boolean readMore = true; while (readMore) { line = fs.readLine(); System.err.println(line); Wenn de Zeile nicht leer ist, wird eine neue Frage erzeugt und der Suchvorgang kann beginnen. Diese Zeile wird nach Semikolonen abgesucht. Wenn die Anzahl dieser 6 ist, ist der Teil vor dem ersten Semikolon die Frage, der Text vom 2. bis zum 5.Teil sind die 4 Antworten und der letzte Teil ist schließlich die korrekte Antwort. if (line!=null) { Frage f = new Frage(); StringTokenizer st = new StringTokenizer(line,";"); if (st.countTokens()==6) { int i = 1; while(st.hasMoreElements()) { String erg = (String)st.nextElement(); if (i==1) f.setFrage(erg); else if (i==2) f.setAntwort1(erg); else if (i==3) f.setAntwort2(erg); else if (i==4) f.setAntwort3(erg); else if (i==5) f.setAntwort4(erg); else if (i==6) f.setKorrekt(Integer.parseInt(erg)); i++; } } Die gesammelten Informationen werden der Hashtable hinzugefügt. con.put("" + j, f); j++; if ((line.length() == 0 )) readMore = false; } else readMore=false; } } catch(Exception e) {System.err.println(e.toString());} } } 74 Frage.java Eine Frage wird erzeugt. package millionenshow; public class Frage { private String frage = ""; private String antwort1 = ""; private String antwort2 = ""; private String antwort3 = ""; private String antwort4 = ""; private int korrekt = 0; public Frage(String f, String a1, String a2,String a3,String a4, int c) { this.frage = f; this.antwort1 = a1; this.antwort2 = a2; this.antwort3 = a3; this.antwort4 = a4; this.korrekt = c; } public Frage() { } Die Frage, die 4 Antwortmöglichkeiten und die korrekte Antwort werden von FragenContainer eingelesen… public String getFrage() {return this.frage;} public String getAntwort1() {return this.antwort1;} public String getAntwort2() {return this.antwort2;} public String getAntwort3() {return this.antwort3;} public String getAntwort4() {return this.antwort4;} public int getKorrekt() {return this.korrekt;} … und übergeben. public void setFrage(String f) {this.frage=f;} public void setAntwort1(String a1) {this.antwort1=a1;} public void setAntwort2(String a2) {this.antwort2=a2;} public void setAntwort3(String a3) {this.antwort3=a3;} public void setAntwort4(String a4) {this.antwort4=a4;} public void setKorrekt(int c) {this.korrekt=c;} } 75 4.2 Ein einfacher Browser Dieses Beispiel stellt einen sehr einfachen Webbrowser dar. Dieser Browser besteht lediglich aus einem Text-Fenster (JEditorPane), das den Inhalt der Webpage anzeigt, einem Textfeld für die URL und einem Button mit dem man zur Startseite zurückkehren kann. Browser.java Die Klassen werden importiert. import javax.swing.*; import javax.swing.event.*; import java.awt.*; import java.awt.event.*; import java.net.*; import java.io.*; Die Klasse Browser implementiert einen HyperlinkListener und einen ActionListener. public class Browser extends JFrame implements HyperlinkListener, ActionListener { 76 Die Startseite wird festgelegt. public static void main(String[] args) { if (args.length == 0) new Browser("http://www.gym1.at/~skumme16/browser.html"); else new Browser(args[0]); } Variablen werden deklariert. private JIconButton homeButton; private JTextField urlField; private JEditorPane htmlPane; private String initialURL; Die Komponenten werden erzeugt und ihnen werden Eigenschaften zugewiesen. Das vom Betriebssystem verwendete Look and Feel wird eingestellt. public Browser(String initialURL) { super("Simple Swing Browser"); this.initialURL = initialURL; addWindowListener(new ExitListener()); WindowUtilities.setNativeLookAndFeel(); JPanel topPanel = new JPanel(); topPanel.setBackground(Color.lightGray); homeButton = new JIconButton("home.gif"); homeButton.addActionListener(this); JLabel urlLabel = new JLabel("URL:"); urlField = new JTextField(30); urlField.setText(initialURL); urlField.addActionListener(this); topPanel.add(homeButton); topPanel.add(urlLabel); topPanel.add(urlField); getContentPane().add(topPanel, BorderLayout.NORTH); Es wird versucht die Startseite aufzurufen. Gelingt dies nicht, wird eine Fehlermeldung ausgegeben. try { htmlPane = new JEditorPane(initialURL); htmlPane.setEditable(false); htmlPane.addHyperlinkListener(this); JScrollPane scrollPane = new JScrollPane(htmlPane); getContentPane().add(scrollPane, BorderLayout.CENTER); } catch(IOException ioe) { warnUser("Can't build HTML pane for " + initialURL + ": " + ioe); } 77 Die Größe des Fensters wird festgelegt. Dimension screenSize = getToolkit().getScreenSize(); int width = screenSize.width * 8 / 10; int height = screenSize.height * 8 / 10; setBounds(width/8, height/8, width, height); setVisible(true); } Wenn die eingegebene URL mit der Entertaste bestätigt wird, wird versucht diese zu erreichen. Schlägt dieser Versuch fehl, wird eine Fehlermeldung ausgegeben. public void actionPerformed(ActionEvent event) { String url; if (event.getSource() == urlField) url = urlField.getText(); else url = initialURL; try { htmlPane.setPage(new URL(url)); urlField.setText(url); } catch(IOException ioe) { warnUser("Can't follow link to " + url + ": " + ioe); } } public void hyperlinkUpdate(HyperlinkEvent event) { if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { try { htmlPane.setPage(event.getURL()); urlField.setText(event.getURL().toExternalForm()); } catch(IOException ioe) { warnUser("Can't follow link to " + event.getURL().toExternalForm() + ": " + ioe); } } } private void warnUser(String message) { JOptionPane.showMessageDialog(this, message, "Error", JOptionPane.ERROR_MESSAGE); } } WindowsUtilities.java Dieses Tool erleichtert das Verwenden von Fenstern und Frames in Swing. import javax.swing.*; import java.awt.*; public class WindowUtilities { public static void setNativeLookAndFeel() { 78 try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch(Exception e) { System.out.println("Error setting native LAF: " + e); } } public static void setJavaLookAndFeel() { try { UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName( )); } catch(Exception e) { System.out.println("Error setting Java LAF: " + e); } } public static void setMotifLookAndFeel() { try { UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel"); } catch(Exception e) { System.out.println("Error setting Motif LAF: " + e); } } /** A simplified way to see a JPanel or other Container. * Pops up a JFrame with specified Container as the content pane. */ public static JFrame openInJFrame(Container content, int width, int height, String title, Color bgColor) { JFrame frame = new JFrame(title); frame.setBackground(bgColor); content.setBackground(bgColor); frame.setSize(width, height); frame.setContentPane(content); frame.addWindowListener(new ExitListener()); frame.setVisible(true); return(frame); } /** Uses Color.white as the background color. */ public static JFrame openInJFrame(Container content, int width, int height, String title) { return(openInJFrame(content, width, height, title, Color.white)); } /** Uses Color.white as the background color, and the * name of the Container's class as the JFrame title. */ 79 public static JFrame openInJFrame(Container content, int width, int height) { return(openInJFrame(content, width, height, content.getClass().getName(), Color.white)); } } JIconButton.java Hier wird einem normalen Button ein Icon angefügt. import javax.swing.*; public class JIconButton extends JButton { public JIconButton(String file) { super(new ImageIcon(file)); setContentAreaFilled(false); setBorderPainted(false); setFocusPainted(false); } } ExitListener.java Bewirkt, dass das Schließen des Frames gleichzeitig auch zum Schließen der Anwendung führt. import java.awt.*; import java.awt.event.*; public class ExitListener extends WindowAdapter { public void windowClosing(WindowEvent event) { System.exit(0); } } 80 4.3 Lotto Dieses Programm lässt eine komplette Lottoziehung nachspielen. Es besteht sowohl die Möglichkeit selbst Tipps abzugeben aber auch diese automatisch erzeugen zu lassen. UML – Notation: 81 Anwendung1.java: Anwendung1.java wird von JBuilder automatisch erzeugt und dient zur Einstellung und Ausrichtung des Frames. package lotto; import javax.swing.UIManager; import java.awt.*; public class Anwendung1 { boolean packFrame = false; //Die Anwendung konstruieren public Anwendung1() { MainScreen frame = new MainScreen(); //Frames überprüfen, die voreingestellte Größe haben //Frames packen, die nutzbare bevorzugte Größeninformationen enthalten, z.B. aus ihrem Layout if (packFrame) { frame.pack(); } else { frame.validate(); } //Das Fenster zentrieren Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); Dimension frameSize = frame.getSize(); if (frameSize.height > screenSize.height) { frameSize.height = screenSize.height; } if (frameSize.width > screenSize.width) { frameSize.width = screenSize.width; } frame.setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height) / 2); frame.setVisible(true); } //Main-Methode public static void main(String[] args) { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch(Exception e) { e.printStackTrace(); } new Anwendung1(); } } 82 MainScreen.java: Das Hauptfenster der Anwendung und gleichzeitig der sichtbare Teil für den Benutzer. package lotto; import java.awt.*; import java.awt.event.*; import javax.swing.*; import com.borland.jbcl.layout.*; import java.util.*; import javax.swing.event.*; Die Klasse MainScreen wird definiert, ein ActionListener und ein ChangeListener werden implementiert. Anschließend werden die Komponenten erzeugt, Variablen deklariert und Layouts zugewiesen. public class MainScreen extends JFrame implements ActionListener, ChangeListener { JPanel contentPane; JMenuBar jMenuBar1 = new JMenuBar(); JMenu jMenuFile = new JMenu(); JMenuItem jMenuFileExit = new JMenuItem(); JMenu jMenuHelp = new JMenu(); JMenuItem jMenuHelpAbout = new JMenuItem(); XYLayout xYLayout1 = new XYLayout(); JPanel jPanel1 = new JPanel(); GridLayout gridLayout1 = new GridLayout(); JPanel jPanel2 = new JPanel(); JButton jButton1 = new JButton(); JButton jButton2 = new JButton(); JButton jButton3 = new JButton(); JPanel jPanel3 = new JPanel(); JList jList1 = new JList(); JList jList2 = new JList(); JPanel jPanel4 = new JPanel(); JLabel jLabel1 = new JLabel(); JSlider jSlider1; int val = 1; XYLayout xYLayout2 = new XYLayout(); JButton jButton4 = new JButton(); Vector v = new Vector(); Vector kor = new Vector(); int[] gezogen = new int[6]; int[] tips = new int[6]; int k=1; JTextField jTextField1 = new JTextField(); JPanel jPanel7 = new JPanel(); JTextField jTextField3 = new JTextField(); XYLayout xYLayout5 = new XYLayout(); 83 JLabel jLabel2 = new JLabel(); JLabel jLabel3 = new JLabel(); XYLayout xYLayout3 = new XYLayout(); JLabel jLabel4 = new JLabel(); //Den Frame konstruieren public MainScreen() { enableEvents(AWTEvent.WINDOW_EVENT_MASK); try { jbInit(); } catch(Exception e) { e.printStackTrace(); } } Die Komponenten werden initialisiert, ihnen werden Eigenschaften zugewiesen. private void jbInit() throws Exception { contentPane = (JPanel) this.getContentPane(); contentPane.setLayout(xYLayout1); this.setSize(new Dimension(1024, 768)); this.setTitle("Lotto"); //Menü jMenuFile.setText("Datei"); jMenuFileExit.setText("Beenden"); jMenuFileExit.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { jMenuFileExit_actionPerformed(e); } }); jMenuHelp.setText("Hilfe"); jMenuHelpAbout.setText("Info"); jMenuHelpAbout.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { jMenuHelpAbout_actionPerformed(e); } }); //Komponenten jPanel1.setLayout(new GridLayout(5,9)); jButton1.setText("Tipp abgeben"); jButton1.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(ActionEvent e) { } }); jButton1.addActionListener(this); jButton2.setText("Zufallstipps erzeugen"); jButton2.addActionListener(this); jButton3.setText("Ziehung"); jButton3.addActionListener(this); jLabel1.setText("Anzahl der Zufallstipps:"); contentPane.setPreferredSize(new Dimension(1024, 768)); 84 jPanel2.setLayout(xYLayout2); jButton4.setText("Vergleiche"); jButton4.addActionListener(this); jPanel7.setLayout(xYLayout5); jTextField3.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(ActionEvent e) { } }); jLabel2.setText("Lottotipps:"); jLabel3.setText("1"); jPanel3.setLayout(xYLayout3); jMenuFile.add(jMenuFileExit); jMenuHelp.add(jMenuHelpAbout); jMenuBar1.add(jMenuFile); jMenuBar1.add(jMenuHelp); jPanel2.add(jButton1, new XYConstraints(10, 5, 144, -1)); jPanel2.add(jPanel4, new XYConstraints(99, 77, -1, -1)); contentPane.add(jPanel2, new XYConstraints(391, 32, 341, 223)); this.setJMenuBar(jMenuBar1); for (int i=1; i<46;i++) { JCheckBox tip = new JCheckBox(""+i); tip.addActionListener(this); jPanel1.add(tip); } jPanel3.add(new JScrollPane(jList1), "Center"); //Slider jSlider1 = new JSlider(JSlider.HORIZONTAL, 0, 20, 1); jSlider1.setMajorTickSpacing(5); jSlider1.setMinorTickSpacing(1); jSlider1.setPaintTicks(true); jSlider1.setPaintLabels(true); jSlider1.setSnapToTicks(true); jSlider1.addChangeListener(this); jPanel2.add(jTextField1, new XYConstraints(163, 5, 117, 26)); jPanel2.add(jSlider1, new XYConstraints(10, 138, 277, -1)); jPanel2.add(jButton2, new XYConstraints(10, 50, -1, -1)); jPanel2.add(jLabel3, new XYConstraints(161, 107, 40, 21)); jPanel2.add(jLabel1, new XYConstraints(19, 108, 140, -1)); contentPane.add(jPanel1, new XYConstraints(18, 14, 322, 332)); contentPane.add(jPanel3, new XYConstraints(779, 37, 226, 218)); contentPane.add(jLabel2, new XYConstraints(782, 20, -1, -1)); contentPane.add(jPanel7, new XYConstraints(170, 453, 331, 210)); contentPane.add(jButton3, new XYConstraints(32, 405, 112, -1)); contentPane.add(jButton4, new XYConstraints(33, 449, 111, -1)); contentPane.add(jTextField3, new XYConstraints(170, 403, 116, 27)); contentPane.add(jLabel4, new XYConstraints(297, 405, 254, 20)); jPanel7.add(new JScrollPane(jList2)); } 85 Die EventListener werden definiert: //ActionListener public void actionPerformed(ActionEvent event) { String cmd = event.getActionCommand(); Das Ereignis „Zufallstipps erzeugen“ wird ausgelöst. Die am Schieberegler eingestellte Anzahl von Tipps wird erzeugt und in der Liste angezeigt. Außerdem werden die einzelnen Zahlen der jeweiligen Tipps in einem Array gespeichert. if (cmd.equals("Zufallstipps erzeugen")) { v.removeAllElements(); for (int j=0;j<val;j++) { Ziehung tip = new Ziehung(); v.addElement(""+tip.getReihe()); jList1.setListData(v); tips[0]=tip.getZahl0(); tips[1]=tip.getZahl1(); tips[2]=tip.getZahl2(); tips[3]=tip.getZahl3(); tips[4]=tip.getZahl4(); tips[5]=tip.getZahl5(); } } Hier werden die korrekten Lottozahlen ermittelt und dann n einem Textfeld ausgegeben. Auch hier werden die einzelnen Zahlen der korrekten Zahlenfolge in einem Array gespeichert. if (cmd.equals("Ziehung")) { Ziehung ziehung = new Ziehung(); jTextField3.setText(""+ziehung.getReihe()); gezogen[0]=ziehung.getZahl0(); gezogen[1]=ziehung.getZahl1(); gezogen[2]=ziehung.getZahl2(); gezogen[3]=ziehung.getZahl3(); gezogen[4]=ziehung.getZahl4(); gezogen[5]=ziehung.getZahl5(); } Der im Lottoschein ausgewählte Tipp wird zur Tippliste hinzugefügt. if (cmd.equals("Tipp abgeben")) { v.addElement(jTextField1.getText()); jList1.setListData(v); } 86 Hier werden die abgegeben Tipps mit den richtigen Lottozahlen verglichen. Die Anzahl der richtigen wird ausgegeben. Außerdem wird jeder Tipp in einer Liste abgespeichert. if (cmd.equals("Vergleiche")) { int n=0; for (int i=0;i<6;i++) { for (int j=i;j<6;j++) { if (tips[i] == gezogen[j]){n=n+1;} } } kor.addElement("Bei Ihrem "+k+".Tipp hatten Sie " +n+" richtige!"); k=k+1; jList2.setListData(kor); jLabel4.setText("Sie haben "+n+" richtige!"); } Die ausgewählten Zahlen im Lottoschein werden in ein Textfeld übergeben. //Checkbox ActionListener for (int i=1; i<46;i++) { if (cmd.equals(""+i)) { String text = jTextField1.getText(); jTextField1.setText("" +text+ "|"+i);; } } } Der variable Wert des Schiebereglers wird einem Label übergeben. //changeListener public void stateChanged(ChangeEvent event) { JSlider jSlider1 = (JSlider)event.getSource(); val = jSlider1.getValue(); if (!jSlider1.getValueIsAdjusting()) { jLabel3.setText(""+ val); } } Hier werden die Ereignisse im Menü festgelegt. Beim klicken auf „Beenden“ schließt das Programm, beim Ausführen von „Info“ wird der „About“-Fenster geöffnet. //Menü //Aktion Datei | Beenden durchgeführt public void jMenuFileExit_actionPerformed(ActionEvent e) { System.exit(0); } //Aktion Hilfe | Info durchgeführt 87 public void jMenuHelpAbout_actionPerformed(ActionEvent e) { Info i = new Info(this); i.show(); } //Überschrieben, so dass eine Beendigung beim Schließen des Fensters möglich ist. protected void processWindowEvent(WindowEvent e) { super.processWindowEvent(e); if (e.getID() == WindowEvent.WINDOW_CLOSING) { jMenuFileExit_actionPerformed(null); } } } Ziehung.java In dieser Klasse erfolgt die Erzeugung der Zahlenfolgen. package lotto; import java.awt.*; import java.awt.event.*; import javax.swing.*; import java.util.*; public class Ziehung { int nummer; String reihe; int[] lottozahlen = new int [6]; int[] kugel = new int[45]; int[] zahl = new int[6]; int i; Das Array „Kugel“ wird mit Zahlen von 1-45 aufgefüllt. public Ziehung() { for(int i=0;i<45;i++) { kugel[i]=i+1; } nummer=0; reihe=""; Sechs zufällige Zahlen werden aus diesem Array ausgewählt. for (int i=0;i<6;i++) { int zug=(int)((45-nummer)*Math.random()); zahl[nummer]=kugel[zug]; nummer++; 88 for(int k=zug;k<44-nummer;k++) { kugel[k]=kugel[k+1]; } } Die sechs ausgewählten Zahlen werden sortiert. for (int j=0;j<5;j++) { for(int i=0;i<5;i++) { if (zahl[i]>zahl[i+1]) { int hilf=zahl[i]; zahl[i]=zahl[i+1]; zahl[i+1]=hilf; } } } Die Zahlen werden aneinandergereiht. for(int i=0;i<6;i++) { reihe=reihe+zahl[i]+"|"; } } Die Zahlenreihe wird zurückgeliefert. Auf diese Methode greifen dann die Ereignisse „Ziehung“ und „Zufallstipps erzeugen“. public String getReihe() { return reihe; } Die einzelnen Zahlen der Zahlenreihe werden separat zurückgeliefert. Die beiden oben genannten Ereignisse benötigen diese Methoden, um die einzelnen Zahlen in ein Array zu speichern. public int getZahl0() { return zahl[0]; } public int getZahl1() { return zahl[1]; } 89 public int getZahl2() { return zahl[2]; } public int getZahl3() { return zahl[3]; } public int getZahl4() { return zahl[4]; } public int getZahl5() { return zahl[5]; } } Info.java Dieses Fenster wird durch Ausführen von „Info“ im Menü geöffnet. Es beinhaltet ledigtlich vier Labels und einen Button zum Schließen des Fensters. package lotto; import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.border.*; import com.borland.jbcl.layout.*; public class Info extends JDialog implements ActionListener { JPanel panel1 = new JPanel(); JPanel insetsPanel1 = new JPanel(); JPanel insetsPanel3 = new JPanel(); JButton button1 = new JButton(); 90 JLabel label1 = new JLabel(); JLabel label2 = new JLabel(); JLabel label3 = new JLabel(); JLabel label4 = new JLabel(); GridLayout gridLayout1 = new GridLayout(); String product = ""; String version = "Version 1.0"; String copyright = "Copyright (c) 2002"; String comments = ""; XYLayout xYLayout1 = new XYLayout(); XYLayout xYLayout2 = new XYLayout(); public Info(Frame parent) { super(parent); enableEvents(AWTEvent.WINDOW_EVENT_MASK); try { jbInit(); } catch(Exception e) { e.printStackTrace(); } pack(); } /**Component initialization*/ private void jbInit() throws Exception { //imageLabel.setIcon(new ImageIcon(MainScreen_AboutBox.class.getResource("[Your Image]"))); this.setTitle("About"); setResizable(false); panel1.setLayout(xYLayout1); insetsPanel1.setLayout(xYLayout2); gridLayout1.setRows(4); gridLayout1.setColumns(1); label1.setText("created by Andreas Kamper"); label2.setText(version); label3.setText(copyright); label4.setText("Lottoziehung"); insetsPanel3.setLayout(gridLayout1); insetsPanel3.setBorder(BorderFactory.createEmptyBorder(10, 60, 10, 10)); button1.setActionCommand("Close"); button1.setText("Close"); button1.addActionListener(this); insetsPanel3.add(label4, null); insetsPanel3.add(label1, null); insetsPanel3.add(label2, null); insetsPanel3.add(label3, null); panel1.add(button1, new XYConstraints(69, 91, 78, -1)); panel1.add(insetsPanel1, new XYConstraints(0, 143, 400, -1)); panel1.add(insetsPanel3, new XYConstraints(7, 1, -1, -1)); this.getContentPane().add(panel1, BorderLayout.EAST); } /**Overridden so we can exit when window is closed*/ protected void processWindowEvent(WindowEvent e) { if (e.getID() == WindowEvent.WINDOW_CLOSING) { cancel(); } super.processWindowEvent(e); 91 } /**Close the dialog*/ void cancel() { dispose(); } /**Close the dialog on a button event*/ public void actionPerformed(ActionEvent e) { if (e.getSource() == button1) { cancel(); } } } 92 5. Entwicklersoftware 5.1 Borland JBuilder 5.0 JBuilder ist das führende Programm zum Erlernen von Java und visueller Entwicklung. Ein umfassendes Tutorial hilft Einsteigern sich schnell zurechtzufinden. 93 Mit der WYSIWYG – Oberfläche im Designmodus fällt die graphische Gestaltung leichter. Mir persönlich hat JBuilder am meisten zugesagt. Das Programm bietet sehr viele Optionen und ist dennoch komfortabel zu bedienen. JBuilder 5.0 ist in der Personal Edition als Freeware erhältlich. 94 5.2 SUN Forte 4 JAVA CE 3.0 Forte 4 Java ist in der Community Edition ebenfalls frei erhältlich. Forte bietet eine ähnliche Design - Oberfläche wie JBuilder. Meiner Meinung nach ist die Bedienung etwas komplizierter und unübersichtlicher. Forte 4 Java kommt in Sachen Komfort nicht ganz an den JBuilder heran. 95 5.3 JavaEditor Der JavaEditor ist meiner Meinung nach ein ideales Einsteigerprogramm für Java, weil die Entwicklungsumgebung sehr übersichtlich und wenig komplex ist. Für das Programmieren von Swing-Anwendungen bzw. von Programmen, bei denen auch auf die graphische Oberfläche Wert gelegt werden muss, ist der JavaEditor allerdings nicht so zu empfehlen. Zumindest steht er IDE’s wie JBuilder 5.0 oder Forte 4 Java 3.0 nach, weil JavaEditor keine WYSIWYG Oberfläche besitzt. Aus diesem Grund wird die graphische Gestaltung auch um einiges schwieriger. 96 6. Literaturverzeichnis Folgende Quellen wurden von mir beim Erstellen dieser Fachbereichsarbeit verwendet: Bücher KRÜGER, Guido: GoTo Java 2 – Handbuch der Java-Programmierung. 2.Auflage. München: Addison-Wesley, 2000 ZUKOWSKI, John: Definitive Guide to Swing for Java 2, Second Edition. Berkeley: Apress, 2000 GUMM, Heinz-Peter, SOMMER Manfred: Einführung in die Informatik. 4.Auflage. München: Oldenbourg, 2000 MÖSSENBÖCK, Hanspeter: Sprechen Sie Java?. Eine Einführung in das systematische Programmieren. Heidelberg: dpunkt.verlag, 2001 TABATT Peter, WOLF Henry: Java programmieren mit JBuilder 4 Frankfurt: Software & Support, 2001 Internet http://java.about.com http://www-lufgi3.informatik.rwth-aachen.de http://developer.java.sun.com http://www.selfjava.de/ http://ada.rg16.asn-wien.ac.at 97 Ich bestätige, dass ich diese Fachbereichsarbeit selbstständig unter ausschließlicher Verwendung der oben angeführten Quellen erstellt habe.