This content was uploaded by our users and we assume good faith they have the permission to share this book. If you own the copyright to this book and it is wrongfully on our website, we offer a simple DMCA procedure to remove your content from our site. Start by pressing the button below!
Die Wahl für professionelle Programmierer und Softwareentwickler. Anerkannte Experten wie z.B. Bjarne Stroustrup, der Erfinder von C++, liefern umfassendes Fachwissen zu allen wichtigen Programmiersprachen und den neuesten Technologien, aber auch Tipps aus der Praxis. Die Reihe von Profis für Profis!
Hier eine Auswahl: Handbuch der Java-Programmierung Guido Krüger, Thomas Stark 1332 Seiten € 49,95 [D], € 51,40 [A] ISBN 978-3-8273-2373-6
Das »Handbuch der Java-Programmierung« ist das deutsche Standardwerk zur Sprache Java schlechthin. Angefangen von absoluten Grundlagen bis hin zu den komplexesten Themen liefern Guido Krüger und Thomas Stark Informationen für Einsteiger, Fortgeschrittene und auch professionelle Java-Programmierer.
Der erfolgreiche Autor Dr. Berthold Daum bringt ein neues Java-Grundlagenbuch auf den Markt, das das Potenzial zum Klassiker hat: objektorientierte Programmierung, Java Generics, Oberflächendesign, Grafik und fortgeschrittene Textbearbeitung, Datenbanken und XML-Verarbeitung, Kommunikation und Webservices, Drucken, Nebenläufigkeit, Lokalisierung, Sicherheit und Entwicklungswerkzeuge sind einige der Themen, die in bewährter Weise aufgenommen und praxisnah erläutert werden.
Ralph Steyer
JavaFX Dynamische und interaktive Java-Applikationen mit JavaFX
An imprint of Pearson Education München • Boston • San Francisco • Harlow, England Don Mills, Ontario • Sydney • Mexico City Madrid • Amsterdam
Bibliografische Information Der Deutschen Bibliothek Die Deutsche Bibliothek verzeichnet diese Publikation in der Deutschen Nationalbibliografie; detaillierte bibliografische Daten sind im Internet über abrufbar. Die Informationen in diesem Produkt werden ohne Rücksicht auf einen eventuellen Patentschutz veröffentlicht. Warennamen werden ohne Gewährleistung der freien Verwendbarkeit benutzt. Bei der Zusammenstellung von Abbildungen und Texten wurde mit größter Sorgfalt vorgegangen. Trotzdem können Fehler nicht vollständig ausgeschlossen werden. Verlag, Herausgeber und Autoren können für fehlerhafte Angaben und deren Folgen weder eine juristische Verantwortung noch irgendeine Haftung übernehmen. Für Verbesserungsvorschläge und Hinweise auf Fehler sind Verlag und Herausgeber dankbar. Alle Rechte vorbehalten, auch die der fotomechanischen Wiedergabe und der Speicherung in elektronischen Medien. Die gewerbliche Nutzung der in diesem Produkt gezeigten Modelle und Arbeiten ist nicht zulässig. Fast alle Hardware- und Softwarebezeichnungen und weitere Stichworte und sonstige Angaben, die in diesem Buch verwendet werden, sind als eingetragene Marken geschützt. Da es nicht möglich ist, in allen Fällen zeitnah zu ermitteln, ob ein Markenschutz besteht, wird das ®-Symbol in diesem Buch nicht verwendet.
Umwelthinweis: Dieses Produkt wurde auf chlorfrei gebleichtem Papier gedruckt. Um Rohstoffe zu sparen, haben wir auf die Folienverpackung verzichtet.
Vorwort Wir schreiben das Jahr 2008. Das Raumschiff Java stößt in neue Galaxien vor, die nie ein Mensch zuvor gesehen hat. Die Sun-Föderation macht sich auf, die JavaFX-Technology der Menschheit zur Verfügung zu stellen und damit neue Welten zu eröffnen. Mit JavaFX wird die beachtliche Erfolgsgeschichte von Java um einen bedeutenden Meilenstein erweitert. Es sieht so aus, als wäre die Zeit reif für Technologien, die auf einfache Weise lokale Computer mit Netzwerken und mobilen Endgeräten verschmelzen und dabei die unterschiedlichsten Plattformen berücksichtigen. Das, was mit Java begonnen hat und zu großen Erfolgen geführt wurde, wird mit JavaFX sowohl fortgeführt als auch vereinfacht und damit einer breiteren Masse an Programmierern zugänglich gemacht. Wobei Sun mit der Konzeption von JavaFX in Bezug auf die Java-Tradition dazu einen doch sehr ungewöhnlichen Weg wählt. Die JavaFX Technology umfasst eine ganze Reihe an Einzeltechnologien (Authoring-Produkten) und tritt mit dem allgemeinen Ziel an, das professionelle Erstellen und Verteilen von interaktiven, multimedialen Inhalten über sämtliche Java-Plattformen hinweg zu erleichtern. JavaFX stellt dazu eine Reihe an neuen Schnittstellen bereit, über die Entwickler die meisten, bereits vorhandenen, JavaBibliotheken auf einfache Weise verwenden können. Vor allem soll JavaFX die Verwendung von Java Swing (Erstellung von Oberflächen) und Java 2D (Grafik) erleichtern.
Vorwort
Der Kern der gesamten JavaFX Technology ist eine auf Java basierende deklarative Skriptsprache mit Namen JavaFX Script. Beim ersten Release von JavaFX war daneben aber auch schon ein Authoring-Produkt für mobile Endgeräte mit Namen JavaFX Mobile integriert. JavaFX gehört explizit in die Familie der Java-Technologien. Sun hat jedoch bei der Konzeption von JavaFX einen Weg gewählt, der mit vielen Traditionen und Paradigmen bricht, die sich über die Geschichte von Java entwickelt haben. Und obwohl viele Quellen als Zielgruppe für JavaFX Java-Programmierer angeben, ist die Konzeption von JavaFX eher so aufgebaut, dass man sie auch ohne Java-Kenntnisse als Voraussetzung verstehen kann. Im Gegenteil – ich vermute, erfahrene Java-Programmierer werden beim Einarbeiten sogar häufiger eine Art Glaubenskrise erleben, wenn sie sich mit JavaFX auseinander setzen. Was in keiner Weise bedeuten soll, dass Java-Kenntnisse nicht von erheblichem Vorteil sind, wenn man JavaFX lernen möchte. JavaFX ist in der Tat mit einem Java-Background leicht zu lernen. Nur muss man auch als erfahrener Java-Programmierer offen für neue (alte) Ideen sein, die mit JavaFX eingeführt werden und wie gesagt mit einigen bestehenden Java-Traditionen radikal brechen. Und diese möglicherweise etwas »mysteriösen« Aussagen möchte ich etwas verdeutlichen, indem ich von mir selbst erzähle. Als ich mich in JavaFX eingearbeitet habe, hatte ich permanent eine Art Déjà-vu-Erlebnisse. In JavaFX tauchen immer wieder Programmiertechniken auf, die es in Java nicht gibt, beziehungsweise geben darf, die ich aber in meinem »ersten Leben« als Programmierer permanent angewendet hatte. Und dieses »erste Leben« fand Anfang der 90erJahre statt. Nach Ende meines Studiums habe ich 1991 bei einer Versicherung als Programmierer angefangen und dort mit Turbo Pascal (also prozedural) gearbeitet. Ich habe versicherungsspezifische DOS-Programme damit erstellt. 1994 sollten wir Programmierer dann – man ist ja modern1 – unbedingt objektorientiert programmieren. Wir wurden also in einer Hauruck-Aktion auf C/C++ umgeschult. Und wie die meisten prozeduralen Programmierer haben wir nach der Umschulung fast alles getan, um bei dieser hybriden Sprache Objekte und Klassen zu umgehen ;-). Die kommenden C/C++-Projekte waren deshalb definitiv weiterhin prozedural strukturiert. Nur gelegentlich wurden ein paar Objekte und Klassen benutzt, wenn es sich einfach nicht verhindern ließ. Unabhängig davon, dass nach der Umschulung das erste große Referenzprojekt, das den Umstieg rechtfertigen sollte, stillschweigend vor der Einführung eingestellt wurde, soll dieser Abstecher in die Geschichte meiner eigenen Programmiererlaufbahn andeuten, dass sich viele Programmierer nur schwer von bekannten und etablierten Techniken auf eine neue Denkweise umpolen lassen. 1
12
;-)
Vorwort
Nun habe ich etwa 1995 mit Java zu programmieren angefangen. Ich dachte zu dem Zeitpunkt, ich könnte bereits objektorientiert programmieren – immerhin hatte ich ja in C/C++ gearbeitet. Nur dummerweise gingen in Java aber die gesamten prozentualen Tricks nicht, mit denen man in C/C++ der wirklichen objektorientierten Denkweise ausweichen kann. Ich musste also tatsächlich objektorientierte Programmierung lernen, um mit Java etwas anfangen zu können. Ich kann Ihnen sagen, dass es ein sehr langsamer und schmerzhafter Lernprozess war, bis ich endgültig von der objektorientierten Programmierung überzeugt war (und sie richtig kapiert habe – zumindest behaupte ich das jetzt mal von mir selbst). Nun sehe ich mich mittlerweile wie ein ehemaliger Raucher (prozeduraler Programmierer), der zum radikalen Nichtraucher (objektorientierter Programmierer) konvertiert ist2. Ich schätze insbesondere das objektorientierte Konzept von Java inzwischen sehr. Es ist nicht so radikal und damit für viele Programmierer praxisfern wie beispielsweise das Konzept von Smalltalk, aber auch nicht so inkonsequent wie das hybride Konzept von C/C++. Java, was sich aus Smalltalk und C/C++ entwickelt hat, vereinigt das Beste aus diesen Welten. Zusätzlich wurden bei der Konzeption von Java die Schwächen der Vorlagen ausgemerzt und einige intelligente Erweiterungen vorgenommen. So weit, so gut. Und jetzt merke ich bei JavaFX, dass dort neben objektorientierten Techniken wieder Ansätze der prozeduralen Programmierung (Funktionen, Prozeduren, etc.) zu einem hybriden Charakter dieser neuen Technologie führen. Und dass an zahlreichen Stellen explizite Konzepte von Java über Bord geworfen werden, die jahrelang als die großen Vorteile von Java dargestellt wurden (Verzicht auf Mehrfachvererbung, Zwang zum expliziten Festlegen von Datentypen, etc.). Um das Beispiel mit dem Raucher fortzuführen: Ich komme mir bei JavaFX vor wie ein ehemaliger Raucher, der sich mühsam das Rauchen abgewöhnt hat, überzeugter Nichtraucher geworden ist und nun erfährt, dass so ein oder zwei Zigaretten am Tag der Gesundheit gar nicht schaden, sondern im Gegenteil sehr förderlich sind. Oder um es noch etwas anders zu formulieren – mit JavaFX musste ich mich vom mittlerweile fast radikalen Anhänger der objektorientierten Java-Programmierung wieder zu einem hybrid denkenden Programmierer »zurückentwickeln«. Ich kann Ihnen sagen, dass das fast genauso schwer wie der Umstieg von der prozeduralen Programmierung zur objektorientierten Programmierung vor über 10 Jahren war. Wieder musste ich mich von einer lieb gewonnenen Technologie bzw. Denkweise verabschieden und eine neue Idee verinnerlichen.
2
Die Konvertierten sind immer die schlimmsten ;-).
13
Vorwort
Wobei »neue Idee« nicht ganz richtig ist – es werden bei JavaFX teilweise wieder uralte und angeblich vollkommen überholte Dinge an Bord geholt, mit denen ich vor meiner objektorientierten Zeit programmiert habe. Einige richtige Déjà-vus. Sowohl was das Auftauchen alter Techniken als auch des mühsamen Lernprozesses betrifft. Beim Einstieg in JavaFX hat mir allerdings sehr geholfen, dass ich neben Java permanent auch in JavaScript und PHP programmiere. Und wenn man als Java-Programmierer die Augen schließt und vergisst, dass JavaFX eigentlich in der Java-Welt beheimatet ist, und sich stattdessen einredet, dass JavaFX ein Vetter von JavaScript ist, kann man die Konzepte von JavaFX auch schmerzlos verdauen. Das ist Sun auch klar, denn sie sagen von JavaFX Script selbst, dass es vom Konzept her JavaScript ähnlicher als Java ist. Und – das möchte ich den Lesern mit Java-Erfahrung von vornherein klarmachen – die Konzepte von JavaFX sind für Programmierer ohne Java-Erfahrung definitiv leichter zu erlernen als die Konzepte von Java selbst. Und diese Aussage soll gerade diesen Lesern Mut machen. Alles in allem ist JavaFX vor allen Dingen aber spannend und öffnet in der Tat neue Welten. Und wenn man letztendlich das gesamte Konzept von JavaFX erfasst und erste Applikationen erstellt hat, sieht man, dass Sun mit dem Bruch von einigen Java-Paradigmen in der Tat viele Vorteile eröffnet. Mir hat die Einarbeitung in JavaFX – trotz gelegentlichen Bauchgrimmens wegen des Bruchs von Java-Traditionen – auf jeden Fall auch viel Spaß gemacht. Und solchen Spaß als auch Erfolg wünsche ich Ihnen ebenso. Ralph Steyer Eppstein www.javafx-buch.de
14
1
Einleitung und Vorbereitung
Der Knaller auf der JavaOne-Konferenz von Sun im Jahr 2007 war ohne Zweifel die Ankündigung der JavaFX Technology oder kurz JavaFX als neue Skripting-Plattform für Web- und Desktop-Applikationen sowie mobile Anwendungen. Wie Rich Green, der Vice President für Software bei Sun, erklärte, steht JavaFX Technology dabei als Überbegriff für ein vollständiges, erweiterbares OpenSource-System zur Entwicklung plattformneutraler JavaApplikationen von der untersten bis zur obersten Entwicklungsebene. Dabei stellt JavaFX Script, das von Sun unter die GPL3Lizenz gestellt wurde, als zentraler Kern der gesamten Technologie die Mittel zur Verfügung, um allgemeine visuelle, hochleistungsfähige Anwendungen auf Basis von Java zu erzeugen. Obwohl auch ganz einfache Applikationen mit Konsolenausgabe erstellt werden können, wurde JavaFX Script eigentlich speziell dafür designed, um den kreativen Prozess der Erstellung von Benutzeroberflächen unter Verwendung von den Java-Techniken Swing, Java 2D und Java 3D zu optimieren. Aber egal welche Art von Applikationen Sie letztendlich erzeugen – JavaFX-Applikationen laufen wie alle JavaApplikationen auf allen Plattformen, die eine passende virtuelle Java-Maschine (JVM – Java Virtual Machine) bereitstellen. Beginnend bei einem Desktopsystem mit
3
GPL steht für (GNU) General Public License und bezeichnet eine Lizenz für freie Software (so genannte Open Source-Software).
Kapitel 1
einem beliebigen Betriebssystem, sofern dieses mit Java SE4 ausgestattet ist, über Home-Entertainment samt Set-Top-Boxen und Blu-ray-Discs bis hin zu mobilen Geräten mit JavaFX Mobile.
Abbildung 1.1: So sieht Sun JavaFX in einem offiziellen Diagramm auf seinen Webseiten
Wobei das Stichwort JavaFX Mobile den zweiten Vertreter der Anfangskonfiguration von JavaFX bezeichnet, der neben JavaFX Script bereits bei der Veröffentlichung zur Verfügung gestellt wurde. JavaFX Mobile bezeichnet das Softwaresystem von Sun für mobile Endgeräte, das über eine OEM-Lizenz zu Verfügung steht. Manche Analysten sehen sogar den gesamten Fokus bzw. chancenreichsten Markt von JavaFX auf dem mobilen Bereich. Aber ob das wirklich so ist, wird natürlich erst die zukünftige Entwicklung von JavaFX und wie es sich gegenüber Konkurrenztechniken in den unterschiedlichen Welten behaupten kann zeigen.
> >
>
HINWEIS
Um es also noch einmal festzuhalten – bei der Einführung von JavaFX umfasst der Begriff sowohl JavaFX Script als auch JavaFX Mobile. Über die Zeit sollen weitere Module zur Produktfamilie von JavaFX hinzukommen, die allesamt die Java-typischen Kriterien »write-once-run-anywhere«, das Sicherheitsmodel für Applikationen, die einheitliche Distribution und die Enterprise-Connectivity aufweisen.
4
16
SE ist die Abkürzung für Standard Edition.
Einleitung und Vorbereitung
JavaFX Script ist – wie der Name ja deutlich macht – zwar eine (hochproduktive) Skriptsprache, hat aber im Wesentlichen dieselbe Codestruktur wie Java, obgleich es sich syntaktisch in diversen Feinheiten unterscheidet. Und das teilweise nicht zu knapp! Aber Wiederverwendbarkeit sowie Pakete, Klassen, Vererbung und separate Kompilierungseinheiten sind beispielsweise direkt mit Java kompatibel. Und nicht nur das – JavaFX Script ist eine Skripting-Umgebung, die den Anbietern von Inhalten erlaubt, direkt auf die Java-Run-Time-Umgebung zuzugreifen. JavaFX Script ist dennoch bewusst keine Allzweck-Programmiersprache wie Java, sondern ähnelt trotz der Zugehörigkeit zur Java-Familie eher HTML oder Javascript5. Sie kann jedoch im Gegensatz zu diesen Technologien auch außerhalb des Browsers ausgeführt werden und hat dort sogar die hauptsächliche Anwendung. Der Fokus der Skriptsprache JavaFX Script besteht auf der möglichst einfachen und schnellen Erstellung von interaktiven und sehr medial aufbereiteten Inhalten und grafischen Benutzeroberflächen. JavaFX Script stellt dazu eine geschlossene Integration mit anderen Java-Komponenten (sowohl Applikationen als auch Infrastruktur) zu Verfügung.
> >
>
HINWEIS
Quelltextdateien in JavaFX Script haben die Dateierweiterung .fx. Auch das grenzt sie deutlich von »normalem« Java-Quellcode ab, der grundsätzlich die Erweiterung .java hat.
JavaFX Mobile verwendet Industriestandard-APIs und -technologien, weshalb Applikationen über einen großen Bereich an Java-fähigen Geräten funktionieren werden.
> >
>
HINWEIS
API steht für Application Programming Interface – Schnittstelle zur Anwendungsprogrammierung.
JavaFX Mobile soll damit im Wesentlichen die Integrationskosten reduzieren und die Einführung von neuen Applikationen in der extrem heterogenen mobilen Welt erheblich beschleunigen.
1.1 Worum es in diesem Buch geht Worum es in diesem Buch geht, ist recht offensichtlich. Dieses Buch soll Ihnen bei dem Einstieg in die Erstellung von plattformneutralen Applikation mit JavaFX bzw. JavaFX Script helfen.
5
Das wird in der Tat in den offiziellen Verlautbarungen von Sun so postuliert. Und zum Teil scheinen sogar Anleihen bei PHP genommen worden zu sein.
17
Kapitel 1
Der eindeutige Fokus liegt dabei auf JavaFX Script als Sprache. Dazu werden im Laufe des Buchs alle relevanten Techniken samt vieler praktischer Beispiele durchgespielt. Das beginnt mit den Voraussetzungen zum Erstellen und Ausführen von JavaFX-Applikationen bei Ihnen als auch einem Anwender Ihrer Applikationen, geht über die Konzepte und die Syntax von JavaFX Script sowie weitergehende Anwendungen. Hier sollen im Schwerpunkt grafische Swing- und 2D-Java-Applikationen besprochen werden. Natürlich beschäftigen wir uns auch mit dem Verteilen von JavaFX-Applikationen. Und da wir uns im Java-Umfeld bewegen, werden wir selbstverständlich permanent verschiedene Aspekte der reinen Java-Programmierung streifen.
1.2 Schreibkonventionen In diesem Buch werden Sie verschiedene Schreibkonventionen finden, die Ihnen helfen sollen, die Übersicht zu bewahren. Wichtige Begriffe werden hervorgehoben. Oder auch so. Vor allem sollten Sie erkennen können, ob es sich bei bestimmten Passagen um normalen Text oder Programmcode handelt. Ebenso werden Tasten ((Alt), (Strg) oder (Shift)) bzw. MENÜBEFEHLE und noch einige weitere Besonderheiten gekennzeichnet. Diese Formatierungen werden konsequent verwendet. Und ebenso werden Sie in dem Buch Bereiche außerhalb des normalen Fließtextes vorfinden, die über die Markierung mit verschiedenen Symbolen besondere Aufmerksamkeit erzeugen sollen.
> >
>
HINWEIS
Das ist ein besonderer Hinweis, den Sie an der Stelle beachten sollten. Oder Sie finden hier eine allgemeine neue Information. Meist wird hiermit ein Begriff erklärt, der zum ersten Mal im Buch auftaucht und von dem nicht vorausgesetzt werden kann, dass ihn jeder Leser bereits kennt. TIPP
Das ist ein Tipp, der spezielle Ratschläge oder besondere Tricks zu einer jeweiligen Situation zeigt.
!
!
!
ACHTUNG
Hier droht Gefahr.
18
Einleitung und Vorbereitung
1.3 Wer ich bin Ich möchte mich Ihnen nun kurz vorstellen. Mein Name ist Ralph Steyer6 und ich bin Diplom-Mathematiker.
Abbildung 1.2: That’s me? – ;-)
Seit 1995 arbeite ich als Freelancer (Fachautor, Fachjournalist, EDV-Dozent und Programmierer). Davor stehen einige Jahre als Programmierer bei einer großen Versicherung im Rhein-Main-Gebiet im Lebenslauf. Meine Erfahrung im Schreiben von Büchern im Internet- und Programmierumfeld reicht bis 1995 und einem ersten HTML-Buch zurück, dem mittlerweile zahlreiche Bücher zu JavaScript, Java, Browsern, Intranet-Administration sowie weiteren Programmierthemen und zuletzt auch PHP, AJAX und XML sowie verschiedenen Google-Technologien wie dem Google Web Toolkit folgten. Daneben übersetze und lektoriere ich hin und wieder auch Bücher von Kollegen.
6
Was Sie vielleicht schon gelesen haben.
19
Kapitel 1
Im privaten Bereich stehen Sport jeglicher Art (von Leichtathletik über Rasenkraftsport, Mountainbiken, Motorradfahren bis zum Gleitschirmfliegen) sowie Saxophonspielen in einer Rockband ganz vorne in der Hitliste – sofern mir die Arbeit und meine Familie die Zeit lassen. Meine Homepage finden Sie unter www.rjs.de, und unter www.ajax-net.de betreibe ich ein Portal zu AJAX. Unter der Internet-Adresse www.javafx-buch.de habe ich speziell zu diesem Buch ein Portal ins Leben gerufen, um dort unter anderem Ergänzungen, Fehlerkorrekturen und ein Forum für Fragen zu JavaFX und dem Buch zur Verfügung zu stellen. Das ist meines Erachtens gerade für dieses Thema besonders wichtig, weil das Buch zu einem ziemlich frühen Zeitpunkt der JavaFX-Entwicklung geschrieben wird und sich deswegen mit ziemlicher Sicherheit noch Änderungen und Erweiterungen ergeben werden.
> >
>
HINWEIS
Dem Buch liegt eine stabile und weitgehend ausgereifte, aber nichtsdestotrotz sehr frühe Betaversion von JavaFX zu Grunde. Es steht zu erwarten, dass die in diesem Buch besprochenen Dinge auch in zukünftigen Versionen vollkommen analog funktionieren werden. Und es ist zu hoffen, dass die Dinge, die in dieser Betaversion noch nicht richtig oder zum Teil gar nicht funktionieren, in einer finalen Version keine Probleme mehr bereiten. Dem Buch liegt eine stabile und weitgehend ausgereifte, aber nichtsdestotrotz sehr frühe Betaversion von JavaFX zu Grunde. Es steht zu erwarten, dass die in diesem Buch besprochenen Dinge auch in zukünftigen Versionen vollkommen analog funktionieren werden. Denn letztendlich sind JavaFX-Applikationen im Kern Java-Applikationen und basieren auf einer Plattform, die seit mehr als 12 Jahren etabliert ist. So gesehen dürfte diese Betaversion weit ausgereifter sein als es typischer Weise für Betaversionen gilt. Und es ist zu hoffen, dass die Dinge, die in dieser Betaversion noch nicht richtig oder zum Teil gar nicht funktionieren, in einer finalen Version keine Probleme mehr bereiten.
1.4 Wer sind Sie, beziehungsweise an wen wendet sich das Buch? Sie wissen jetzt so ungefähr, wer Sie durch die Einarbeitung in JavaFX begleiten will. Aber ich habe auch gewisse Vorstellungen von Ihnen. Wer könnte sich für JavaFX eigentlich interessieren? Das Buch wendet sich einmal an die große Gruppe der Webseitenersteller beziehungsweise Webprogrammierer, die mithilfe einer an Java orientierten Skriptsprache multimedial aktive Web-Applikationen erstellen wollen. Und dies losgelöst von HTML (Hypertext Markup Language) beziehungsweise XHTML (eXtensible Markup Language), CSS (Cascading Style Sheets), und JavaScript sowie dem DOM-Konzept7. 7
20
Document Object Model
Einleitung und Vorbereitung
Genau genommen wollen wir mit JavaFX sogar die Fesseln eines Browsers sprengen. JavaFX-Applikationen werden in der Regel nicht viel mit einem Webbrowser zu tun haben. Aber auch (zukünftige) Programmierer für Desktop-Applikationen fallen ausdrücklich in die Zielgruppe für dieses Buch, wenn sie einen Weg suchen, auf einfache Weise mächtige Java-Techniken wie Swing oder Java 2D anzuwenden, ohne Java direkt anwenden zu müssen und/oder zu tief in Java einsteigen zu wollen. Nicht zu vergessen sind Programmierer, die für die Erstellung von Applikationen für mobile Endgeräte einen einfachen und komfortablen Weg suchen. JavaScript bietet sich ebenso hervorragend als Grundlage für den Einstieg in JavaFX an. Entsprechend werden sich JavaScript-Programmierer mit JavaFX eine sehr gute Alternative aufbauen können, um die Leistungsfähigkeit des Java-APIs zu verwenden. Und natürlich dürften auch vor allem Java-Programmierer an JavaFX interessiert sein, um ihr allgemeines Java-Repertoire zu erweitern. Nun wurde die Zielgruppe mehrfach mit »Programmierer« bezeichnet. Dennoch handelt es sich bei diesem Buch ausdrücklich um ein Einsteigerbuch. Um es kurz zu fassen – Sie müssen für den Umgang mit diesem Buch beileibe kein Programmierprofi sein. Und Kenntnisse in Java werden auch, wie ausdrücklich gesagt, nicht vorausgesetzt! Auf die notwendigen Grundlagen wird im Rahmen des Buchs eingegangen. Dennoch fange ich in dem Buch nicht bei Adam und Eva an. Etwas grundlegende Erfahrung in einer (beliebigen) Programmiersprache oder Skriptsprache ist auf jeden Fall Voraussetzung. Ebenso werde ich nicht weiter auf Details zu HTML, XHTML, CSS oder XML eingehen. Geringe Grundlagen werden auch hier vorausgesetzt, sofern dies im Laufe des Buchs relevant wird.
> >
>
HINWEIS
Die Quelltexte für sämtliche Beispiele, die Sie in dem Buch finden, finden Sie auf der Buch-CD. Die Beispiele sind nach Kapiteln geordnet und in Projektordnern abgelegt. Die Quelltexte für sämtliche Beispiele die Sie in dem Buch finden, finden Sie auf der Buch-CD. Die Beispiele sind nach Kapiteln geordnet und in Projektordnern abgelegt. Lauffähige Versionen für diverse Beispiele können Sie direkt per Internet über die Seite www.javafxbuch.de starten. Dort finden Sie auch ergänzende Beispiele samt Quelltexten.
1.5 Was benötigen Sie? Wenn Sie nun mit JavaFX Ihre Programme erstellen wollen, müssen natürlich gewisse Voraussetzungen bei Ihnen erfüllt sein.
21
Kapitel 1
1.5.1 Die Hardware Sie benötigen selbstverständlich zu einer erfolgreichen Arbeit mit dem Buch erst einmal einen Computer. Das ist trivial. Allerdings sollte dieser nicht zu schwach auf der Brust sein. Wir arbeiten mit JavaFX auf Basis einer Java-Umgebung und die fordert einigermaßen Power von dem ausführenden Rechner. Zusätzlich werden Sie unter Umständen Entwicklungsprogramme verwenden, die grundsätzlich ebenso ziemlich Leistung fordern. Glücklicherweise kostet ein moderner Computer mit wenigstens 1 GByte RAM und einem Prozessor, der mindestens der Pentium 4-Generation angehört, heutzutage nicht mehr viel Geld. Für eine zügige Arbeit unter Java und den meisten besseren Entwicklungstools empfehle ich allerdings auf jeden Fall einen Computer mit Mehrkernprozessor und mindestens 2 GByte Hauptspeicher. Im Grunde kann Ihre Hardware bei Programmierung gar nicht leistungsfähig genug sein. Und Sie sollten auf jeden Fall einen (möglichst schnellen) Zugang zum Internet haben. Das betrachte ich als selbstverständlich.
1.5.2 Die Java-Basisumgebung Nun wird es interessanter. Wir bewegen uns mit JavaFX natürlich im Java-Umfeld. Java-Applikationen benötigen eine spezielle Laufzeitumgebung, damit sie ausgeführt werden können. Und das bedeutet, dass Sie auf Ihrem Computer auf jeden Fall eine so genannte Java Laufzeitumgebung (JRE – Java Runtime Environment) benötigen. Genauso wie jeder Anwender, der eine Java- beziehungsweise JavaFX-Applikation ausführen möchte. Eine solche Java-Laufzeitumgebung gibt es mittlerweile für fast jedes moderne Betriebssystem8. Bei vielen Betriebssystemen wird sie sogar bereits in der Grundausstattung zur Verfügung gestellt. Möglicherweise haben Sie aber nicht die passende Version installiert. Aber auch aus anderen Gründen müssen wir auf die JRE und die genaue Version noch etwas detaillierter eingehen. Wir wollen ja nicht nur Java- bzw. JavaFX-Applikationen ausführen, sondern selbstverständlich auch erstellen. Und dazu benötigen wir mehr als nur eine Laufzeitumgebung.
8
22
Und auch für mobile Geräte wie Handys oder andere technische Geräte des täglichen Lebens.
Einleitung und Vorbereitung
Wir brauchen entsprechende Entwicklungstools für Java respektive JavaFX. Im Kern bedeutet das, dass wir erst einmal minimal ein aktuelles Java Entwicklungspaket (das so genannte Java SE Development Kit oder nur Java Development Kit – abgekürzt JDK9) benötigen. Und das müssen Sie sich erst einmal besorgen.
1.5.3 Download des JDK Sämtliche für uns relevanten Java-Technologien (sowohl zur reinen Ausführung einer Java- bzw. JavaFX-Applikation als auch der Entwicklung) bekommen Sie bei Bedarf unentgeltlich von den Java-Seiten von Sun Microsystems unter http://java.sun.com. Auf diesen speziell zum Java-Universum gestalteten Seiten finden Sie einen Link, der Sie zum Download-Bereich führt.
Abbildung 1.3: Downloads zu Java
9
In diversen Quellen redet man auch vom Java SDK – Software Development Kit. Das wird selbst auf den offiziellen Java-Seiten von Sun leider sehr inkonsistent gehandhabt.
23
Kapitel 1
Sie müssen lediglich vor einem Download der meisten Features die Lizenzbedingungen für die Verwendung akzeptieren – eine Registrierung oder etwas Ähnliches ist nicht notwendig. Es gibt das JDK für verschiedene Betriebssysteme (im Wesentlichen verschiedene Versionen von Windows und Linux beziehungsweise Solaris, aber auch weitere Betriebssysteme wie MacOS), wobei wir uns im Folgenden auf Windows und Linux konzentrieren werden.
!
!
!
ACHTUNG
Für das, was wir in der Folge tun wollen, werden wir ein JDK der Version 5.0 oder besser 6 voraussetzen. Das ist für JavaFX auch zwingend notwendig.
Sie sollten also auf jeden Fall zuerst einmal ein JDK der Version 5 oder 6 auf Ihrem Rechner installiert haben. Damit schlagen Sie mehrere Fliegen mit einer Klappe, denn diese Java-Entwicklungssysteme enthalten neben den eigentlichen Entwicklungstools alle eine vollständige Java-Laufzeitumgebung zum Ausführen von Java-Applikationen, die wie gesagt auch die Basis zum Ausführen von JavaFX-Applikationen ist.
1.5.4 Die Installation der Java-Basisumgebung Die Installation der Java-Umgebung respektive des JDK ist absolut unproblematisch. Sie werden bei allen neueren Java-Versionen von einem typischen Installationsassistenten für Ihr Betriebssystem geführt. Dieser richtet alle notwendigen Einstellungen in Ihrem Betriebssystem ein. Anschließend sind auf Ihrem Rechner die passenden Verzeichnisse vorhanden und die Systemeinstellungen zum Ausführen von Java-Applikationen und den JDK-Tools angepasst. Mehr muss man zur Installation definitiv nicht mehr sagen. Das JDK selbst besteht aus einer ganzen Reihe von Programmen, die sich nach der Installation im Unterverzeichnis bin des JDK-Installationsverzeichnisses befinden. Dort können Sie sie über die Befehlszeilenebene mit eventuell benötigten Parametern aufrufen. TIPP
Wenn Sie ein Programm des JDK ohne Parameter aufrufen, erhalten Sie in der Konsole Hinweise zu den optionalen und ebenso zu den zwingenden Parametern.
Zu den Basisprogrammen des JDK im engeren Sinn zählen der Compiler (javac), der Interpreter (java bzw. javaw), der Appletviewer, ein Debugger (jdb), das Dokumentations-Tool javadoc und das Java Archive Tool mit Namen jar.
24
Einleitung und Vorbereitung
1.5.5 Mobiles Java und JavaFX auf mobilen Endgeräten Der Markt der programmierbaren mobilen Endgeräte ist riesig und Java schon geraume Zeit eine ideale Plattform dafür. Das hat Sun schon sehr früh erkannt10. Und mit JavaFX steht Ihnen nun eine Technik zur Verfügung, mit der die Erstellung von solchen mobilen Applikationen erleichtert werden soll. JavaFX ist ja auch ausdrücklich dafür designed worden, dass insbesondere auch die Erstellung von Java-Applikationen für mobile Endgeräte erleichtert werden soll. Nun werden wir im Laufe des Buchs aber dennoch nur an sehr wenigen Stellen explizit auf mobiles Java eingehen, denn es ist ja das Wesen von Java und JavaFX, dass die Zielplattform keine zentrale Rolle spielt11. Sie werden also mehr oder weniger alle Beispiele in dem Buch auch auf mobile Endgeräte portieren können, wenn die Endgeräte die Möglichkeiten dazu bieten. Das Thema ist sozusagen immer implizit mit eingeschlossen. Allerdings umfasst die Erstellung mobiler Applikationen so viele Besonderheiten, dass dies den Rahmen des Buchs bei weitem sprengen würde. Wir müssen und werden uns darauf beschränken, dass Sie in JavaFX einfach auf Klassen des mobilen Umfeldes genauso zugreifen können wie auf alle anderen Klassen in der Java-Welt. Dennoch möchte ich Sie nicht gänzlich ohne Erklärungen bezüglich der mobilen Welt von Java lassen, sondern zumindest kurz auf die grundsätzliche Erstellung von so genannten MIDLets eingehen.
> >
>
HINWEIS
Mobile Java-Applikationen werden allgemein auch MIDlets genannt, was bezüglich der Namensgebung durchaus in die Tradition von Applets und Servlets passt, die Sun im Laufe der Java-Historie für client- und serverseitige Internet-Applikationen eingeführt hatte.
Die Erstellung eines MIDlets unterscheidet sich auf der einen Seite nur unwesentlich von der Erstellung eines Applets12 oder Servlets13, die einer größeren Entwicklerschaft auch eher bekannt sind. Auf der anderen Seite unterscheiden sich MIDlets aber in gewissen Details der noch sehr stark von anderen Java-Applikationen, weil die Umgebung, in der ein MIDlet ausgeführt wird, sehr stark differieren kann14. Dabei muss beachtet werden, dass man diese Abweichung zwischen den verschiedenen Plattformen auf den ersten Blick sogar möglicherweise nicht sieht. Ein weiteres Problem ist die 10 Wie schon erwähnt – die eigentliche Motivation für Java war die Erzeugung einer Plattform für diesen Markt. 11 Der Fokus dieses Buches liegt ganz klar auf der Sprache JavaFX Script. 12 Eine Java-Applikation, die in einem Webbrowser läuft. 13 Eine Java-Applikation, die in einem Java-fähigen Server ausgeführt wird. 14 Es gibt bekanntlich unzählige mobile Endgeräte mit ganz verschiedenen Rahmenbedingungen.
25
Kapitel 1
Usability (Bedienbarkeit) einer Applikation auf einem mobilen Endgerät. Sowohl kleine Bildschirmanzeigen als auch die unterschiedlichsten Eingabemöglichkeiten durch den Anwender (denken Sie nur an die verschiedenen Möglichkeiten einer Handytastatur) machen die Erstellung eines vernünftig zu bedienenden MIDlets komplizierter, als es auf den ersten Blick erscheinen mag. Insbesondere das Design des MIDlets (sowohl die optische Darstellung der Oberfläche als auch des Aufbaus) kann sowohl hoch kompliziert als auch extrem auf ein einzelnes Gerät spezialisiert sein.
Die J2ME Um für solche Geräte jedoch Java-Anwendungen im Allgemeinen und letztendlich auch JavaFX-Applikationen erstellen zu können, benötigen Sie bei Bedarf neben dem JDK ein weiteres Entwicklungspaket. Die Java 2 Micro Edition (J2ME) kombiniert eine ressourcenschonende JVM mit einem Satz an Java-APIs zur Entwicklung von Applikationen für mobile Endgeräte (mobile devices). Die J2ME kann in drei Bestandteile unterteilt werden: 1. Konfiguration 2. Profil 3. Optionale Pakete Die Konfiguration enthält die JVM15 und einige Klassenbibliotheken wie CLDC16 oder CDC17. Aufsetzend auf dieser Basisklassenbibliothek stellt ein Profil einige spezielle weitere APIs wie MIDP18 oder Foundation Profile bereit. Die optionalen Pakete sind weitere APIs, die Sie unter Umständen brauchen können oder auch nicht (etwa 3D API oder Mobile Media API). Diese optionalen Pakete werden traditionell nicht auf der Infrastruktur der späteren Zielhardware zur Verfügung gestellt und müssen deshalb bei Bedarf mit ihrer Applikation ausgeliefert werden. Die Konfiguration und das Profil sind hingegen auf einer Zielplattform für mobile Java-Applikationen grundsätzlich bereits eingebettet. Für die meisten mobilen Java-Applikationen werden das Profil MIDP und die Konfiguration CLDC eingesetzt. CLDC ist insbesondere für solche Endgeräte gedacht, die stark in ihrer Leistungsfähigkeit eingeschränkt sind. Beispielsweise solche Geräte, die nur zwischen 128 bis 512 KB Speicher für Java-Applikationen bereitstellen können. Entsprechend ist die JVM sehr stark limitiert und unterstützt nur eine kleine Anzahl an traditionellen Java-Klassen19. 15 Das ist nicht die traditionelle JVM, wie sie bei Java-Applikationen im Desktop-Bereich zum Einsatz kommt, sondern eine reduzierte Spezialversion für mobile Endgeräte. 16 Connected Limited Device Configuration 17 Connected Device Configuration 18 Mobile Information Device Profile 19 Diese limitierte JVM wird derzeit KVM (Kilobyte Virtual Machine) genannt.
26
Einleitung und Vorbereitung
Die erweiterte Version CDC verwendet man für solche Endgeräte, die mindestens 2 MB Speicher zu Verfügung haben. Entsprechend werden mehr Features unterstützt. MIDP stellt eine Komplettierung der CLDC-Konfiguration dar und minimiert sowohl den Speicher als auch die Power, die in beschränkten Endgeräten vonnöten sind. Das Profil stellt das Basis-API zu Verfügung, das zur Erstellung von Applikationen für solche Endgeräte vonnöten ist. Beispielsweise wird das Paket javax.microedition.lcdui dort zu finden sein. Dieses erlaubt die Erstellung von Elementen einer grafischen Oberfläche, die dann auf einem beschränkten Endgerät auch angezeigt werden können, wenn das Profil MIDP aufsetzend auf der CLDC-Konfiguration zu Verfügung steht.
> >
>
HINWEIS
MIDP kann nicht mit CDC-Devices verwendet werden. Für CDC-Devices gibt es andere Profile wie Foundation und Personal.
Bezug und Installation des J2ME Development Kit Wenn Sie mit der Entwicklung von Applikationen für die J2ME-Plattform beginnen wollen, müssen Sie lediglich das kostenlose J2ME Wireless Toolkit 2.220 auf Ihrem Entwicklerrechner installieren. Dieses Toolkit enthält alle wichtigen Tools zur Erstellung von MIDlets. Dies umfasst die Entwicklungsumgebung für MIDP 2.0 und CLDC 1.121 sowie die optionalen Pakete, die von den optionalen Bibliotheken benötigt werden (etwa 3D Java und Mobile Media). Und last but not least enthält das Toolkit die Fähigkeit zum Signieren der MIDlets, damit sie vor einer Installation auf dem entfernten mobilen Endgerät authentifiziert werden können22. Sie erhalten das J2ME Wireless Toolkit unter dem URL http://java.sun.com/products/sjwtoolkit/download-2_2.html.
> >
>
HINWEIS
Vor einem Download des Toolkits müssen Sie sich allerdings bei Sun registrieren.
!
!
!
ACHTUNG
Vor der Installation des J2ME Wireless Toolkit muss zuerst das Java Development Kit (JDK) in der Version 1.4.2 oder neuer bereits installiert sein.
20 Beziehungsweise gegebenenfalls eine neuere Version, wenn diese zur Verfügung steht. 21 Aufgrund der Abwärtskompatibilität beinhaltet das auch MIDP 1.0 und CLDC 1.0. 22 Immerhin werden mobile Applikationen auf sensiblen Endgeräten wie Handys mit Organizer etc. installiert.
27
Kapitel 1
Sobald Sie die Installationsdatei für Ihr Betriebssystem geladen haben, kann das Toolkit in ein beliebiges Verzeichnis installiert werden. Das ist wie beim JDK vollkommen unproblematisch.
Abbildung 1.4: Download des J2ME Wireless Toolkit
Die grundsätzliche Erstellung eines MIDlets > >
>
HINWEIS
Die nachfolgenden Ausführungen sind nun speziell für Java-Programmierer gedacht, die aber noch nie ein MIDlet erzeugt haben. Ohne geeignete Java-Vorkenntnisse können Sie diesen Abschnitt überspringen.
28
Einleitung und Vorbereitung
Die Erstellung eines MIDlets beruht auf sieben zentralen Arbeitsschritten, die sich so immer wieder wiederholen: 1. Design 2. Kodierung 3. Kompilierung 4. (Pre-)Verifizierung 5. Packen 6. Testen 7. Auslieferung
Die Klasse MIDlet Jedes MIDlet muss die abstrakte Klasse javax.microedition.midlet.MIDlet erweitern. Dies ist der Dreh- und Angelpunkt der gesamten Technologie. Damit muss ein MIDlet minimal die Methoden startApp(), pauseApp() und destroyApp(boolean unconditional) überschreiben, die in der Klasse definiert werden. Nachfolgend sehen Sie ein einfaches Beispiel für ein MIDlet, das Sie so in jedem beliebigen Klartexteditor erstellen können und das wir auch gar nicht weiter erläutern wollen – das gleitet dann zu sehr in Java ab: 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20
public class DatumZeitMidlet extends MIDlet { Alert timeAlert; public DatumZeitMidlet() { timeAlert = new Alert("Eine Mitteilung"); timeAlert.setString("Aktuelles Datum und aktuelle Uhrzeit:\n " + new Date().toString()); } public void startApp() { Display.getDisplay(this).setCurrent(timeAlert); } public void pauseApp() { }
29
Kapitel 1 21 public void destroyApp(boolean unconditional) { 22 } 23 } Listing 1.1: Der Java-Code für ein beispielhaftes MIDlet
Wenn Sie die Entwicklungsumgebung für MIDlets installiert haben, sehen Sie zahlreiche interessante Beispiele, die Sie auch mithilfe eines integrierten Emulators auf Ihrem lokalen Computer ausführen können. Dazu brauchen Sie in der Regel bloß die .jad-Datei per Doppelklick auszuwählen.
Abbildung 1.5: Ein MIDlet, das in einem Emulator auf einem Windows-PC ausgeführt wird
30
Einleitung und Vorbereitung
Bei dieser .jad-Datei handelt es sich um eine Klartextdatei, die die benötigten Ressourcen für das MIDlet beschreibt. So könnte eine Datei aussehen: 01 MIDlet-1: Life3D,,com.superscape.m3g.wtksamples.life3d.Life3D 02 MIDlet-2: PogoRoo,,com.superscape.m3g.wtksamples.pogoroo.PogoRooMIDlet 03 MIDlet-3: RetainedMode, ,com.superscape.m3g.wtksamples.retainedmode.RetainedModeMidlet 04 MIDlet-Description: Test application for the Swerve engine Java API. 05 MIDlet-Jar-Size: 95110 06 MIDlet-Jar-URL: Demo3D.jar 07 MIDlet-Name: Demo3D 08 MIDlet-Vendor: Superscape Ltd. 09 MIDlet-Version: 1.0 10 MicroEdition-Configuration: CLDC-1.1 11 MicroEdition-Profile: MIDP-2.0 Listing 1.2: Eine .pad-Datei
> >
>
HINWEIS
Um ein wenig vorzugreifen – auch JavaFX-Applikationen werden Ressourcen auf eine ähnliche Weise (allerdings in Form von XML) bündeln.
Letztendlich handelt es sich also bei einem MIDlet nur um Java-Code, den Sie in JavaFX Script vollkommen analog verwenden können wie auch anderen Java-Code. Und genauso können Sie beispielsweise Swing-Oberflächen oder 2D-Grafiken, die mit JavaFX Script erzeugt werden, in einem MIDlet verwenden.
1.5.6 Die Laufzeitumgebung für JavaFX und das JavaFX Script PlugIn Das waren die Basisinstallationen für Java. Um nun Applikation mit JavaFX erstellen respektive ausführen zu können, benötigen Sie über die JRE bzw. das JDK und gegebenenfalls die JME hinaus grundsätzlich eine Erweiterung der normalen Java-Umgebung. Bei JavaFX müssen sowohl die spezifischen Skriptbefehle von JavaFX Script interpretiert als auch ergänzende Bibliotheken in Form von neuen Paketen verfügbar gemacht werden. Mit anderen Worten – Sie benötigen eine zusätzliche Laufzeitumgebung für JavaFX als Erweiterung der normalen Java-Laufzeitumgebung. Es gibt nun mehrere Wege, wie Sie diese Erweiterung installieren können. Diese beruhen darauf, dass Sie sich eine geeignete Entwicklungsumgebung für JavaFX-Applikationen besorgen. Wir werden uns im folgenden Kapitel vier Wege ansehen: 1. Den Einsatz der JavaFX Shell 2. Die Verwendung von JavaFXPad
31
Kapitel 1
3. Ein JavaFX-PlugIn für Eclipse 4. Ein JavaFX-PlugIn für NetBeans Bevor Sie sich aber nun an den Download und die Einrichtung der konkreten Laufzeitumgebung für JavaFX machen, werden wir uns im nächsten Kapitel der JavaFX-Technologie erst einmal etwas nähern.
32
2
Der erste Kontakt
Sie brennen sicher darauf, mit JavaFX anzufangen (hoffe ich mal). Dann sorgen wir in Kürze für den ersten Kontakt. Aber vor der Praxis müssen Sie sich noch kurz durch etwas Theorie arbeiten23, um die Zielsetzung und das Umfeld von JavaFX einordnen zu können.
2.1 Java und Sun – die graue Eminenz hinter JavaFX JavaFX ist als freies System auf Basis von Java konzipiert. Aber dahinter steht nichtsdestotrotz immer noch eine Firma, die schon mehrfach erwähnt wurde – Sun. Wer sich im Umfeld von Java bewegt, sollte ein bisschen was über diese Firma und vor allen Dingen die Geschichte von Java wissen, die bis ins Jahr 1990 zurückgeht. Sun war (und ist) einer der führenden Hersteller von Workstations, die auf dem Unix-Betriebssystem Solaris und Sparc-Prozessoren basieren. Um das Jahr 1990 startete Sun ein Projekt, in dem der zukünftige Bedarf für EDV analysiert werden sollte, um einen zukunftsträchtigen Markt für Sun zu lokalisieren. Haupterkenntnis des Projektes24 war, dass die Computerzukunft nicht im Bereich der Großrechner (soweit nichts Besonderes, denn dies ahnten auch damals schon andere), jedoch auch nicht unbedingt bei den PCs zu sehen ist (und dies war damals neu und nicht unumstritten). 23 Ich hoffe nicht quälen :-). 24 Codename war Green.
Kapitel 2
Der Consumerbereich der allgemeinen Elektronik (Telefone, Videorecorder, Waschmaschinen, Kaffeemaschinen und eigentlich alle elektrischen Maschinen, welche Daten benötigten) war nach Ansicht des Forschungsprojektes der Zukunftsmarkt der EDV. Also ein extrem heterogenes Umfeld, für das ein neues, plattformunabhängiges Gesamtsystem zur Ausführung von Applikation gefordert war. Und dieses musste zudem eine erheblich größere Fehlertoleranz, eine leichtere Bedienbarkeit und eine bedeutend bessere Stabilität als bis dato vorhandene Systeme aufweisen. Aus dieser Analyse entwickelte sich über verschiedene Irrungen und Wirrungen Java, das im März 1995 der Öffentlichkeit präsentiert wurde. Zuerst als Technologie für das Internet wahrgenommen, entwickelte sich Java bis heute zu einer Rundumlösung für alle Aspekte der Programmierung auf heterogenen Plattformen.
2.1.1 Das Konzept von Java Java ist von seiner Syntax auf C aufgebaut, einer Programmiersprache, die stark polarisiert. Sie ist sehr leistungsfähig, gilt aber bei vielen Programmierern als extrem kompliziert und fehleranfällig. Die Konzeption und die Objektorientiertheit bei Java lehnen sich im Wesentlichen an Small Talk an. Auch diese Sprache polarisiert, da sie gänzlich anders konzipiert war als alle anderen vergleichbaren Sprachen der Epoche, in der Small Talk entstanden ist. Beide Vorgängersprachen reichen nämlich bis in die 70er Jahre zurück. Sun hat nun mit der Konzeption von Java einige Fehler seiner Vorfahren vermieden, die zu dieser jeweiligen Polarisierung geführt haben. Es wurde stattdessen versucht, die Stärken der Vorfahren zu nehmen, die über die Jahre bekannt gewordenen Schwächen auszumerzen und dann noch fehlende, sinnvolle Innovationen hinzuzufügen. So war der eine Java-Ahn von Anfang an objektorientiert (Small Talk), hat sich jedoch über die Zeit kaum verbreitet. Ein Grund war wohl die bereits angedeutete vollständige Andersartigkeit von Small Talk gegenüber anderen damals etablierten Programmiersprachen wie C, PASCAL, Basic, COBOL oder FORTRAN. Small Talk ist so radikal objektorientiert, dass beispielsweise keine primitiven Berechnungen wie 5 + 2 mehr direkt möglich sind, sondern ein Umweg über Objekte notwendig ist. Auch verwendet Small Talk teilweise eine sehr eigene Syntax. Bei Java machte Sun nicht den Fehler von Small Talk (und vermied so ein gänzlich radikales Konzept), sondern definiert sich von der Syntax wie gesagt an dem sehr weit verbreiteten C. Alleine diese Syntaxnähe erleichterte vielen Programmierern einen Einstieg. Und auch zu der objektorientierten C-Erweiterung C++ wurde – trotz der konzeptionellen Anlehnung an Small Talk – eine erhebliche Nähe eingehalten, was für diverse Programmierer einen Umstieg weiter erleichterte. Der Umstieg von C/C++ auf Java stellt also für die meisten Entwickler keinen großen Aufwand dar.
34
Der erste Kontakt
Aber im Vergleich zu C und C++ wurden bei Java einige Dinge abgeschafft bzw. nicht realisiert, die im Laufe der Geschichte von C und C++ viel Unheil angerichtet haben. So wurde in Java z. B. keine Mehrfachvererbung realisiert, was Java-Programme viel besser wartbar macht25. Und es wurde das hybride Konzept von C/C++ vermieden. Obwohl man mit C/C++ objektorientiert programmieren kann, untergräbt die Möglichkeit des prozeduralen (altbekannten) Programmierens bei C/C++ den strengen objektorientierten Gedanken. Java lässt einem Programmierer diese Wahl nicht. Man kann wie in Small Talk nur objektorientiert programmieren. Und von C hat sich Java wie gesagt zwar die Syntax geliehen, sich aber diverser Altlasten entledigt. Damit ist Java syntaktisch erheblich einfacher geworden, ohne viel an Leistungsfähigkeit zu verlieren. Java fehlen im Wesentlichen ziemlich üble C/C++Möglichkeiten wie Zeiger, Operator-Overloading, manuelle Speicherverwaltung (d. h. das Speichermanagement, also das Beschaffen und das Freigeben von Speicher durch den Programmierer), automatische Konvertierung von Datentypen, Headerdateien, Pre-Prozessoren, Strukturen, Variant-Datentypen und multidimensionale Arrays. Und was kam bei Java heraus? Java hat mittlerweile einige der wichtigsten Probleme moderner Programmierung gelöst. Kernprinzipien von Java sind die Eigenschaften kompakt, zuverlässig, portierbar, dezentral, echtzeitfähig und integriert. Die offizielle Definition von Sun Microsystems zu Java lautet folgendermaßen: Java: eine einfache, objektorientierte, dezentrale, interpretierte, stabil laufende, sichere, architekturneutrale, portierbare und dynamische Sprache, die HochgeschwindigkeitsAnwendungen und Multithreading unterstützt. Auf diesen Grundsätzen setzt nun auch das neueste Kind der Java-Familie – JavaFX – auf.
2.2 JavaFX im Vergleich zur Konkurrenz Nach der Vorstellung von JavaFX durch Sun stellten sich natürlich sehr schnell Fragen: In welchem Umfeld ist JavaFX zu sehen? Mit welchen bestehenden Technologien konkurriert JavaFX? Wie unterscheidet sich JavaFX von diesen? Die Beantwortung dieser Fragen fasst die Einsatzmöglichkeiten von JavaFX sehr griffig.
25 Interessanterweise erlaubt JavaFX wieder Mehrfachvererbung. Das müssen wir aber genauer ausführen – diese Tatsache ist nicht so schlimm, wie es erfahrene Java-Programmierer im ersten Moment vermuten mögen.
35
Kapitel 2
Als Konkurrenztechnologien zu JavaFX wurden sehr schnell AJAX (Asynchronous Javascript and XML), aber auch Adobe Flash sowie Microsoft Silverlight und Adobe Apollo angeführt. Und auch von Sun selbst gibt es mit dem Projekt Flair eine Technologie, deren Zielstellung sich teilweise durchaus ähnlich beschreiben lässt wie die von JavaFX. Ob aber JavaFX tatsächlich in Konkurrenz zu diesen Technologien steht, müssen wir etwas genauer beleuchten.
2.2.1 AJAX und JavaFX Das Jahr 2006 war in der EDV respektive dem World Wide Web zweifelsohne das Jahr von AJAX. Ein Modewort, das wie ein Sommer-Hit eingeschlagen ist26. Mittlerweile ist AJAX im Web voll etabliert, der Hype ist aber abgeflacht und es verliert als Buzzword sogar schon wieder seine Bedeutung. Das bedeutet nicht, dass AJAX nicht mehr wichtig ist! Im Gegenteil – die Möglichkeiten von AJAX werden im Web schlicht und einfach selbstverständlich. Und damit können sich aber auch andere Lösungen etablieren, die mit abweichenden Techniken arbeiten und die gleichen beziehungsweise ähnliche oder auch ergänzende Möglichkeiten bereitstellen. AJAX löste bei seinem Auftauchen27 über konventionelle und bereits lange flächendeckend im Web unterstützte Techniken ein Hauptproblem des WWW – die Notwendigkeit, bei der Anforderung von neuen Daten durch einen Browser immer eine vollständige neue Webseite laden zu müssen. Dies war auf Grund der fehlenden dauerhaften Verbindung zwischen Sender und Empfänger ohne AJAX (bzw. proprietäre Lösungen) bis dato leider immer notwendig. AJAX bezeichnet nun einen Ansatz, bei dem es möglich ist, nur den Teil einer Webseite vom Server anzufordern, der auch wirklich ausgetauscht werden muss. Ausschließlich mittels Techniken aus dem Umfeld von DHTML28 (XHTML29 beziehungsweise HTML30, XML31, JavaScript und Style Sheets) werden neue Daten vom Server angefordert und die neuen Inhalte in den zu aktualisierenden Teil der Webseite befördert. Die Teile der Webseite, die nicht erneuert werden müssen, können dabei erhalten bleiben. Der zentrale Part ist hierbei JavaScript, um damit den DOM (Document Object Model) einer Webseite zu manipulieren. Es ist offensichtlich, dass die zu versendende Datenmenge des Servers beim Ändern einer Webseite damit erheblich reduziert werden kann. Vor allen Dingen kann das Antwortverhalten von sehr interaktiven Webapplikation bei der Interaktion mit einem Anwender außerordentlich beschleunigt werden. 26 Und auch ich habe mit einigen Büchern davon profitiert :-). 27 Von Auftauchen zu reden, ist fast ein bisschen übertrieben. Der Begriff fasst nur Möglichkeiten zusammen, die sich über längere Zeit im Web bereits gebildet hatten. 28 Dynamic HTML 29 Extensible Hypertext Markup Language 30 Hypertext Markup Language 31 eXtensible Markup Language
36
Der erste Kontakt
AJAX-Applikationen ähneln in ihrem Antwortverhalten im besten Fall mehr Desktopdenn Internet-Applikationen. So gesehen ist AJAX auch eine der zentralen Technologien, um in der kommenden Zeit Desktop- und Internet-Applikationen zu verschmelzen beziehungsweise dem Anwender den Unterschied zu verschleiern. Bei einer AJAX-Applikation kommunizieren nicht nur der Browser und der WebServer direkt miteinander, sondern unabhängig von dieser Kommunikation kann ein Objekt in der Webseite mit dem Server kommunizieren. Dieses Objekt vom Typ XMLHttpRequest zur Kommunikation ist eine Erweiterung des JavaScript-Objektmodells und der Kern jeder AJAX-Anwendung. Die Unterstützung für dieses Objekt in allen wichtigen modernen Browsern ist übrigens die einzige halbwegs neue Technologie, die mit AJAX wirklich eingeführt wurde32.
> >
>
HINWEIS
Ich wage übrigens die Behauptung, dass AJAX niemals ohne den griffigen Namen so erfolgreich geworden wäre. Hätte man die Möglichkeiten von AJAX einfach im Rahmen einer neuen, in allen relevanten Browsern unterstützten JavaScript-Version eingeführt, wäre das Konzept kaum so eingeschlagen.
Aber wie positioniert sich nun JavaFX im Vergleich zu AJAX? JavaFX basiert zum einen explizit nicht auf JavaScript samt einem Konglomerat aus Style Sheets und HTML, sondern eben Java. Dies ist der zentrale technische Unterschied und dieser bringt für JavaFX diverse Vorteile. Obwohl ich mich ausdrücklich als JavaScript-Fan outen möchte, kann auch ich nicht leugnen, dass das Konzept von JavaScript über weite Bereiche inkonsistent ist. Und es fehlen der Technologie einige grundsätzliche Möglichkeiten. Vor allem in Hinsicht auf objektorientierte Programmierung. Das größte Problem ist jedoch, dass JavaScript so gut wie immer in einem inhomogenen Umfeld aus XHTML beziehungsweise HTML, Style Sheets und den DOM sowie unter sehr inkonsistenten Verhaltensweisen verschiedener Webbrowser eingesetzt wird. Das Java-Umfeld ist demgegenüber sowohl homogener als auch logischer, konsequenter und nicht zuletzt objektorientiert. Beim Vergleich von AJAX mit JavaFX muss man ebenso ausdrücklich festhalten, dass die Einsatzmöglichkeiten von JavaFX nicht auf die Alternative zu AJAX beschränkt sind, sondern im Gegenteil viel weiter gehen. Insbesondere in Hinsicht auf die Visualität von Applikationen sowie das Verlassen eines umgebenden Browsers, auf den AJAX grundsätzlich eingeschränkt ist. So gesehen würde ich AJAX und JavaFX entgegen diverser Meldungen in verschiedenen Medien überhaupt nicht als Konkurrenztechniken bezeichnen.
32 Obwohl auch das nicht ganz richtig ist – ein erstes Objekt mit ähnlicher Funktionalität wurde bereits 1997 von Microsoft erstmals vorgestellt.
37
Kapitel 2
2.2.2 JavaFX versus Flair Flair bezeichnet eine Open-Source-Entwicklungsumgebung rein auf Basis von JavaScript, die von Sun im Gegensatz zu JavaFX ausdrücklich als direkte Konkurrenz zu AJAX entwickelt wurde. Für das Flair-Projekt findet man im Internet häufiger die recht einfache Definition: »AJAX without the DOM, CSS and HTML«
Der Unterschied zwischen JavaFX und Flair ist damit ziemlich offensichtlich. JavaFX basiert wie gesagt explizit nicht auf JavaScript, sondern eben Java. Und JavaFX ist wie ebenfalls schon erwähnt im Gegensatz zu Flair nicht nur als spezialisierte Alternative zu AJAX zu sehen, die im Rahmen eines Browsers ausgeführt wird, sondern viel universeller33. Damit steht Flair in Konkurrenz zu AJAX, aber nicht zu JavaFX.
2.2.3 JavaFX und Microsoft Silverlight sowie Moonlight Sun erwähnt ausdrücklich Silverlight von Microsoft als unmittelbares Konkurrenzprodukt zu JavaFX. Unter diesem Bezeichner Silverlight versucht Microsoft eine Webpräsentationstechnik einzuführen, die bis April 2007 noch unter dem Codename WPF/ E (Windows Presentation Foundation/Everywhere) geführt wurde. Die Technik basiert – wie der Name schon klarmacht – auf der WPF (Windows Presentation Foundation), wurde aber erheblich schlanker konzipiert. Silverlight soll der einfachen Darstellung und Animation von Oberflächen aus grafischen Elementen und Mediadaten in einem Browsern dienen. Dazu muss in einem Browser ein entsprechendes PlugIn installiert sein. Die Darstellung von SilverlightInhalten erfordert jedoch explizit keinen Windows Media Player oder auch keine .NET-CLR. Wie WPF basiert Silverlight auf XAML34 (eXtensible Application Markup Language) – einer XML-basierenden Sprache zur Beschreibung und Erstellung von Oberflächen. Für die Umsetzung von dynamischen Aktionen ist im Konzept von Silverlight die Unterstützung von JavaScript vorgesehen.
> >
>
HINWEIS
Genauere Informationen zu Silverlight finden Sie zum Beispiel auf den Microsoft-Seiten im Internet unter http://www.microsoft.com/germany/partner/produkte/web/silverlight.mspx.
33 Es scheint aktuell sogar so zu sein, dass der universellere Ansatz von JavaFX Flair die Luft abschnürt, denn man findet derzeit im Internet kaum Stoff zu Flair. Aber ich kann mich natürlich täuschen. Prognosen, ob sich eine Technologie durchsetzt oder nicht, sind immer sehr gewagt. 34 XAML gilt als Ersatz für GDI/GDI+ – Graphics Device Interface.
38
Der erste Kontakt
Abbildung 2.1: Informationen zu Silverlight aus erster Hand
TIPP
Auch für Linux gibt es eine Umsetzung von Silverlight, die auf Mono basiert. Das Projekt trägt den Namen Moonlight. Informationen dazu gibt es unter http://www.mono-project.com/ Moonlight.
Wenn man nun JavaFX und Silverlight gegenüberstellt, muss man Silverlight mit der expliziten Unterstützung von JavaScript und AJAX, Visual Basic, C#, Python, Ruby etc. eine bedeutend breitere Sprachbasis zugestehen. JavaFX wird hingegen nicht auf eine Plattform (auf das WWW und ein neueres Windows) beschränkt, was bei Silverlight trotz ergänzenden Projekten wie Moonlight ein gravierendes Manko bleibt. Und auch die Fokussierung bzw. Beschränkung auf einen Browser samt unbedingt notwendigem PlugIn wie in Silverlight ist bei JavaFX wie schon erwähnt nicht gegeben.
39
Kapitel 2
2.2.4 Der andere Hauptkonkurrent Adobe mit Flash und Apollo Mit Adobe schwimmt neben Microsoft ein weiterer Hecht im Karpfenteich, in dem Sun möglichst erfolgreich wildern möchte. Dabei müssen gleich zwei Technologien von Adobe dem Angriff von JavaFX standhalten: Flash und Apollo. Flash, was ehemals von Macromedia entwickelt wurde, bezeichnet eine proprietäre integrierte Entwicklungsumgebung zur Erstellung und Darstellung multimedialer Inhalte auf Basis des SWF-Formats. Dies ist Grafik- und Animationsformat auf Vektorbasis, das mit einem speziellen Abspielprogramm (einem Flash Player) verarbeitet werden kann. Seit der Version 4 kann man in Flash-Animation mit der Skriptsprache ActionScript programmieren.
> >
>
HINWEIS
An Flash scheiden sich im Web die Geister. Für die einen ist es eine einfache und leistungsfähige Multimedia-Technologie, für die anderen den Inbegriff nervender Intros und unerwünschter Multimedia-Attacken in Webseiten. Für den schlechten Ruf haben vor allen Dingen die Webseiten gesorgt, die Flash im Übermaß eingesetzt haben. Die Unterstützung von Flash ist im Internet indessen dennoch recht weit verbreitet. Adobe gibt über 90% an, was sicherlich weit, weit überzogen ist. Aber insbesondere Angebote wie YouTube haben in der letzten Zeit für eine echte Renaissance von Flash gesorgt.
Apollo wiederum bezeichnet eine plattformübergreifende Runtime zur Erstellung einer Rich Internet Application (RIA).
> >
>
HINWEIS
Unter einer Rich Internet Application versteht man eine interaktive Web-Anwendung, die im Gegensatz zu einer konventionellen Web-Anwendung »reichhaltige« Möglichkeiten wie z. B. Drag&-Drop, Bedienung über Tastenkürzel, etc. bereitstellt und performanter als eine klassische WebAnwendung bei einer Interaktion mit dem Anwender reagiert. Allgemein wird eine RIA nicht auf dem Client installiert.
Einen guten Einstieg zu Apollo finden Sie unter http://labs.adobe.com/wiki/index.php/ Apollo:Documentation:Getting_started. Dabei können verschiedene Programmier- und Beschreibungsprachen mit Darstellungsstandards und Webtechnologien kombiniert werden (Flash, Flex, JavaScript, HTML, AJAX etc.). Vor allen Dingen führt Adobe mit Apollo Web- und Desktop-Applikationen zusammen, um die Vorteile beider Welten zu verschmelzen. Apollo-Applikationen lassen sich wie einfache Webapplikation direkt aus dem Netz aufrufen, bieten aber typische Desktop-Fähigkeiten wie die Unterstützung von Drag-&-Drop und die Zwischenablage. Insbesondere laufen sie wie herkömmliche Applikationen im Umfeld des Desktops und nicht eingebettet in einen
40
Der erste Kontakt
Browser oder eine andere Interpretationsapplikation. Zur Darstellung von ApolloInhalten soll35 das KHTML-basierende WebKit von Apple zum Einsatz kommen. Wenn wir auch hier wieder JavaFX im Vergleich zu Flash und Apollo betrachten, kann man bei Flash samt ActionScript zwar eine gewisse Ähnlichkeit in der Ausrichtung beobachten, aber eigentlich sind JavaFX und Apollo die direkten Gegner. Sie fokussieren beide ziemlich genau das gleiche Ziel. Nur dürfte die Fokussierung von JavaFX auf die weit verbreitete Java-Plattform erhebliche Vorteile in einer schnellen Einführung bedeuten. Dazu kommt die Vermeidung eines Konglomerats verschiedener Techniken.
2.2.5 JavaFX im Vergleich zu Java-Applets und anderen Sun-Projekten mit ähnlicher Zielsetzung Betrachten wir nun JavaFX noch im Vergleich zu einigen anderen Versuchen von Sun auf Basis von Java, die eine ähnliche Zielrichtung hatten. Die Älteren unter uns werden sich noch an Java-Applets erinnern ;-). Und vielleicht an gewisse Experimente von Sun wie den Net-PC oder Netz-PC.
> >
>
HINWEIS
Im Gegensatz zu Applets ist der Netz-PC von Sun aber vielleicht doch nicht ganz so im Gedächtnis hängen geblieben und möglicherweise einigen Leuten wirklich nicht mehr bekannt. Es ging darum, ein Endgerät für den Anwender auf Java-Basis zu Verfügung zu stellen, das außer einem JavaBetriebssystem keine relevante Software installiert hatte und nicht einmal über eine Festplatte verfügte beziehungsweise verfügen musste. Die gesamte Software als auch die Daten sollten im Netz bereitgestellt und gespeichert werden. Das Projekt ist grandios gescheitert (aus verschiedenen Gründen – die damalige Übertragungsgeschwindigkeit im Internet, psychologische Probleme der Anwender, die damalige Performance von Java etc.), aber die Idee dahinter erlebt aktuell unter dem Begriff Thin Client mittels verschiedener Techniken eine gewaltige Renaissance (obgleich hier oft keine ganze Applikation zum Client übertragen wird, sondern nur eine Benutzerschnittstelle, um auf einem Server Dinge auszuführen).
Auch diese auf Java basierenden Technologien hatten im Wesentlichen den Anspruch, Desktop- und Netzapplikationen zu verschmelzen beziehungsweise Netz- respektive Webapplikationen erweiterte Funktionalitäten zur Verfügung zu stellen. Diese Zielsetzung finden Sie hier in ähnlicher Form ja bei JavaFX wieder. Sie werden aber sicher alle wissen, dass nahezu sämtliche proprietäre Ansätze mit dieser Zielsetzung im World Wide Web in den letzten Jahren gescheitert sind. Nicht nur die von Sun auf Basis von Java, sondern auch von anderen Herstellern.
35 Dies muss etwas vorsichtig formuliert werden, denn zum Zeitpunkt der Bucherstellung ist auch Apollo noch in einer sehr frühen Betaphase.
41
Kapitel 2
Erst AJAX hat es wirklich geschafft, zumindest das World Wide Web bezüglich Interaktivität tatsächlich um einen Meilenstein voranzubringen36. Und warum? Weil es sich auf einen kleinsten gemeinsamen Nenner aus etablierten und einfachen Standardtechniken und einen Webbrowser als Ausführungsplattform beschränkt. Aber genau diese Beschränkung (sowohl auf das World Wide Web als auch relativ wenig leistungsfähige Techniken) ist doch wieder ein Problem, das nun über weitergehende proprietäre als auch offene Ansätze (wie oben beschrieben) gelöst werden soll. Man muss deutlich festhalten – insbesondere Java-Applets hätten schon lange Applikationen im Web gestattet, die weit über das hinausgehen, was mittels AJAX heutzutage zur Verfügung gestellt wird. Der Net-PC war bereits ein Thin Client in Vollendung. Und auch die Verbindung mit Desktop-Applikationen beziehungsweise Applikationen auf mobilen Endgeräten ist mit Java schon lange möglich. Und dennoch fehlte bisher der durchschlagende Erfolg beziehungsweise man muss eben im Fall von Applets und dem Net-PC beispielsweise sogar vom Scheitern sprechen. Warum macht Sun nun aber einen erneuten Anlauf, wo bisherige Ideen bereits mehrfach gescheitert sind? Und warum könnte Sun dieses Mal mehr Erfolg haben? Nun – Java-Applets oder auch Net-PC waren zum einen jeweils ihrer Zeit einfach voraus. Die Infrastruktur mit einem langsamen Internet, noch nicht ausreichend leistungsfähigen Rechnern beim Anwender und mangelnder Java-Unterstützung in gewissen Betriebssystemen hat den Erfolg einfach torpediert. Ebenso ist die Komplexität von Java nicht zu unterschätzen. Auf der einen Seite ist es für einen professionellen Programmierer eine der wohl schönsten und logischsten Programmiersprachen überhaupt, aber für einen Webseitenersteller ohne echte Programmiererfahrung oder einen prozeduralen Programmierer ist der Einstieg beispielsweise dennoch nicht einfach. JavaFX wird nun in einem gepflügten Feld ausgesät und zudem hat Sun aus den Fehlern der Vergangenheit gelernt. Das Internet und die moderne Computerhardware sind hinreichend schnell, Java-Applikationen lassen sich auf fast allen Betriebssystemen ausführen und mobile Endgeräte verfügen auf breiter Front über Java-Unterstützung. Und als Skriptsprache ist JavaFX zudem viel einfacher zu lernen als Java selbst. Zudem gibt es mittlerweile eine sehr große Anzahl an Java-Programmierern, die sich recht einfach JavaFX aneignen können. Alles in allem sind also die Voraussetzungen für JavaFX derzeit um ein Vielfaches besser, als sie für alle bisherigen Ansätze von Sun mit dieser Zielsetzung waren.
36 Denken Sie nur an Applikationen wie Google Maps.
42
Der erste Kontakt
2.3 Kommandozeilenentwicklung und die JavaFX Shell Kommen wir nun zum ersten direkten Kontakt mit JavaFX. Obwohl es mittelfristig dringend zu empfehlen ist, dass Sie sich zur Entwicklung von JavaFX-Applikationen eine integrierte Entwicklungsumgebung (IDE) besorgen37, können Sie im Grunde wie bei anderen Java-Applikationen auch mit einem beliebigen Texteditor und Kommandozeilen-Tools arbeiten. Das ist zwar sehr unbequem und in der Regel auch sehr fehlerträchtig, aber machbar und beim Einstieg in die Technologie aus didaktischen Gründen sogar sehr sinnvoll.
> >
>
HINWEIS
Eine IDE (Integrated Development Environment – auf Deutsch Integrierte Entwicklungsumgebung) bezeichnet eine Programmierumgebung mit Editor, Vorschau, eventueller grafischer Erstellung von Quellcodestrukturen, Fehlersuchmöglichkeit etc. Das bedeutet, unter einer Oberfläche werden verschiedene Tools bzw. Funktionalitäten für die unterschiedlichen Aspekte bei der Entwicklung einer Applikation zusammengefasst. Der Programmierer kann über diese zentrale Oberfläche alle Dinge machen, die bei der Entwicklung einer Applikation notwendig sind, ohne die zentrale Oberfläche zu verlassen oder ein zusätzliches Programm separat aufzurufen.
2.3.1 Download und Installation der JavaFX Shell Auch die Kommandozeilen-Tools für JavaFX müssen Sie erst einmal besorgen und installieren, bevor Sie die ersten JavaFX-Applikationen laufen lassen können. Der Kern dieser einfachen Entwicklungstools ist die so genannte JavaFX Shell, die Sie samt weiterer Utilities als komprimierte Datei38 über den URL39 https://openjfx.dev.java.net/servlets/ProjectDocumentList kostenlos laden können. Wenn Sie diese komprimierte Datei dann auf Ihrem Rechner extrahieren, erhalten Sie in einem zentralen Ordner verschiedene Unterverzeichnisse.
37 Eine solche integrierte Entwicklungsumgebung werden wir auch im Laufe des Buchs fast immer voraussetzen. 38 Als .tgz- oder als .zip-Datei. 39 Uniform Resource Locator – das vereinheitlichte Adressierungsschema, wie es im Internet verwendet wird.
43
Kapitel 2
Abbildung 2.2: Download der JavaFX Shell
Abbildung 2.3: Die extrahierte Datei
TIPP
Unter https://openjfx.dev.java.net/source/browse/openjfx/ steht auch alternativ ein Quellcode-Repository zur Verfügung. Darauf gehen wir aber nicht weiter ein.
44
Der erste Kontakt
Die wichtigsten Strukturen sind im Verzeichnis trunk angesiedelt. Dort finden Sie unter anderem das Unterverzeichnis bin, das die JavaFX Shell beziehungsweise die zugehörigen Aufrufapplikationen javafx.sh40 und javafx.bat41 enthält. Damit können Sie JavaFX-Applikationen ausführen, wenn Sie diese als Argumente angeben42. Des Weiteren sind in diesem Verzeichnis Beispiele, Bibliotheken, eine Dokumentation und verschiedene Quelltexte zu finden. TIPP
Wenn Sie die JavaFX Shell häufiger auf Kommandozeilenebene verwenden wollen, erweitern Sie am besten die Pfadangabe von Ihrem Betriebssystem (PATH) um das Unterverzeichnis trunk/bin. Das macht man unter Unix/Linux-Systemen beispielsweise so: export PATH=$PATH://trunk/bin Listing 2.1: Exportieren des erweiterten Pfads
Unter Windows läuft das zum Beispiel wie folgt: PATH=%PATH%;C:\< Pfad zum Verzeichnis >\trunk\bin Listing 2.2: Erweiterung des Pfads unter Windows
Selbstverständlich können Sie aber auch in der Kommandozeilenebene mit absoluten Pfadangaben zu der Shell- bzw. Batch-Datei arbeiten.
2.3.2 Die Dokumentation des JavaFX Script APIs Sämtliche Klassen des JavaFX Script APIs sind in einer hervorragenden Dokumentation beschrieben, die eine analoge Struktur aus HTML und CSS wie die Dokumentationen der anderen Java-APIs hat und mit jedem Browser angesehen werden kann. Obwohl wir am Anfang noch nicht viel mit speziellen Klassen von JavaFX arbeiten, sollten Sie sich bereits an dieser Stelle die Adresse merken43, wo Sie die Dokumentation des JavaFX Script APIs finden. Sie steht zum Zeitpunkt der Bucherstellung unter dem URL https://openjfx.dev.java.net/nonav/api/index.html zur Verfügung.
40 Ein Shell-Skript für Linux/Unix. 41 Eine Batch-Datei für Windows. 42 Diese beiden Dateien übernehmen im Fall von JavaFX in etwa das, was der Java-Interpreter bei »normalen« Java-Applikationen macht. Allerdings sind die JavaFX-Dateien Klartext. 43 Setzen Sie sich zum Beispiel ein Lesezeichen im Browser.
45
Kapitel 2
Abbildung 2.4: Die Dokumentation des JavaFX Script APIs
2.3.3 Anpassen der Batch-Datei javafx.bat unter Windows In der dem Buch zu Grunde liegenden Version der JavaFX Shell ist noch ein ergänzender Schritt unter Windows notwendig, bevor Sie eine JavaFX-Applikation über den Aufruf der Batch-Datei ausführen können. Sie müssen in der Batch-Datei javafx.bat eine Erweiterung des Klassenpfads vornehmen. Sie finden dort eine Zeile der folgenden Art: %java% %opts% %debug% %opengl% -classpath %~dp0../javafxrt/src/javafx Listing 2.3: Die originale Zeile
Diese muss wie folgt erweitert werden: %java% %opts% %debug% %opengl% -classpath .;%~dp0../javafxrt/src/javafx Listing 2.4: Die erweiterte Version
46
Der erste Kontakt
Erkennen Sie überhaupt die Erweiterung? Es ist der winzige Punkt (.) hinter –classpath und vor dem Zeichen %. Damit binden Sie explizit das aktuelle Verzeichnis in dem Klassenpfad ein.
> >
>
HINWEIS
Es ist mir nicht ganz offensichtlich, warum man von Hand diese Erweiterung vornehmen muss. Ich gehe davon aus, dass dieser Schritt in zukünftigen Versionen von JavaFX nicht mehr notwendig ist. Beachten Sie dazu dann einfach die jeweilige Readme-Datei. Aber im Grunde arbeitet man auch wie gesagt nur am Anfang zum Lernen kurz mit diesen Kommandozeilentools.
2.3.4 Die erste JavaFX-Applikation Nun sollten wir testen, ob jetzt auf Ihrem Rechner ein JavaFX-Programm überhaupt ausgeführt werden kann. Dazu erstellen wir ohne weitere Vorbereitung einfach eine erste einfache JavaFX-Applikation. TIPP
Die Kommandozeilentools für JavaFX enthalten keinen eigenen Editor. Das ist aber kein Problem. Ein beliebiger Texteditor genügt zur Eingabe des Quellcodes.
Beginnen wir mit einem üblichen Hallo-Welt-Programm, dem Sie, wie hier beim Speichern der Datei, den Namen HelloWorld.fx geben wollen. Nachfolgend sehen Sie den Quellcode, den Sie an dieser Stelle einfach abtippen sollten.
> >
>
HINWEIS
Die Details zu dem Quelltext und den syntaktischen Regeln von JavaFX Script etc. werden wir erst an späterer Stelle besprechen. Sonst müssten wir uns viel zu lange durch diverse Passagen von JavaFX Script quälen, bevor Ihr erstes Programm läuft. Sie sollen mit dem Beispiel nur testen, ob JavaFX bei Ihnen funktioniert, und einen ersten knappen Eindruck von JavaFX Script bekommen. Sie müssen allerdings beim Abtippen unbedingt drauf achten, dass Sie strikt Groß- und Kleinschreibung einhalten und sämtliche Kommata, Klammern, Punkte, Doppelpunkte, Semikolons etc. exakt so notieren, wie Sie es im nachfolgenden Listing sehen. Die Nummerierung der jeweiligen Zeilen darf jedoch nicht angegeben werden! Diese ist nur für die bessere Lesbarkeit des Quelltexts und potentielle Erklärungen bestimmter Bestandteile eines größeren Listings gedacht. Sollte eine Zeile im Quelltext einmal länger sein, als es im Buch gedruckt werden kann, und in die nächste Zeile fortgesetzt werden müssen, erkennen Sie dies an der unterbrochenen Nummerierung. Das gilt auch für sämtliche weiteren Listings im Buch.
47
Kapitel 2 01 import javafx.ui.*; 02 03 Frame { 04 title: "Meine erste JavaFX-Applikation" 05 width: 300 06 height: 100 07 content: Label { 08 text: "Willkommen in der Welt von JavaFX" 09 } 10 visible: true 11 } Listing 2.5: Das erste JavaFX-Programm
Zum Quelltext gibt es nur eine ganz knappe Erklärung. Wir erzeugen aus einer Standardklasse von JavaFX ein Objekt, das einem Java-Fenster entspricht, und zeigen es an.
Das erste Programm ausführen Das Ausführen des Programms erfolgt jetzt über das Shell-Skript oder die Batch-Datei, indem Sie die Datei mit dem Namen der Quellcodedatei als Parameter aufrufen. Also auf Unix-Systemen so, wenn Sie sich in dem Verzeichnis befinden, in dem der Quelltext gespeichert ist: javafx.sh HelloWorld.fx Auf Windows-Systemen wäre dies der Programmaufruf: javafx.bat HelloWorld.fx Diese Aufrufe können Sie sowohl in einer Konsole als auch über einen grafischen Ausführen-Dialog, wie er etwa unter Windows im Startmenü zu finden ist, durchführen.
> >
>
HINWEIS
Gegebenenfalls müssen Sie mit absoluten Pfadangaben arbeiten. Dies betrifft einmal die Startdatei, wenn Sie die JavaFX Shell nicht dem Suchpfad Ihres Betriebssystems hinzugefügt haben, aber auch die Quelltextdatei, wenn Sie nicht in dem Verzeichnis stehen, in dem der Quelltext gespeichert ist.
Wenn bei Ihnen nun alles richtig konfiguriert ist und Sie keinen Fehler im Quelltext gemacht haben, sollten Sie nach dem Start der JavaFX-Applikation ein Fenster sehen, das mit der angegebenen Titelzeile und dem spezifizierten Inhalt versehen ist.
48
Der erste Kontakt
Abbildung 2.5: Die erste JavaFX-Applikation mit einem Fenster
Herzlichen Glückwunsch – Sie haben Ihre erste JavaFX-Applikation zum Laufen gebracht.44 TIPP
Die JavaFX Shell samt den zugehörigen Tools ist gut geeignet, wenn Sie eine JavaFX-Applikation später in Produktion bringen wollen – sprich bei einem Anwender zum Laufen bringen wollen – das so genannte Deployment44. Sie liefern die gesamte Laufzeitumgebung einfach mit aus und schreiben gegebenenfalls eine Batch- oder Shell-Datei oder eine andere ausführbare Datei (zum Beispiel eine EXE) zum Aufruf der Applikation, die alle notwendigen Pfadangaben etc. enthält. Um für eine JavaFX-Applikation bei einem Anwender eine Laufzeitumgebung zur Verfügung zu stellen, können Sie aber auch auf das unter https://openjfx.dev.java.net/source/browse/ openjfx/ verfügbare Quellcode-Repository verweisen. Dann benötigen Sie aber natürlich beim »Kunden« auf jeden Fall einen Internet-Zugang, auf den die Applikation beim Start zugreifen kann. Ebenso sollten Sie diesen Verweis wieder in eine Aufrufdatei (eine Batch- oder Shell-Datei oder eine andere ausführbare Datei) verpacken. Die genauen Details zum Verteilen einer JavaFX-Applikation besprechen wir in Kapitel 6.
2.4 Die Verwendung von JavaFXPad Die Arbeitsweise mit einem primitiven Klartexteditor und über die Kommandozeile ist definitiv unbequem. Ich denke, da stimmen Sie mir uneingeschränkt zu. Erleichtern wir uns die Arbeit erst einmal mit dem JavaFXPad-Editor. Bei JavaFXPad handelt es sich um eine so genannte Java Web Start-Applikation.
2.4.1 Wichtige neue Begriffe als Grundlagen Nun wird vor einer näheren Erklärung von JavaFXPad aber die Einführung einiger neuer Begriffe notwendig.
44 Das ist aber nicht die einzige Möglichkeit, eine JavaFX-Applikation zu deployen.
49
Kapitel 2 4546
> >
>
HINWEIS
Die Technik der Java Web Start-Applikationen wurde von Sun schon vor geraumer Zeit eingeführt, um eine Java-Anwendung direkt über das Internet oder ein lokales Intranet zu starten. Genau genommen wird eine solche Java-Anwendung beim Aufruf aus dem Netz heruntergeladen und dann ohne eine Installation auf dem Client ausgeführt45. Java Web Start ist eine Standardkomponente jeder neueren Java Runtime Environment (JRE) und wird zusammen mit JRE seit der Version 1.4.2 automatisch installiert. Das bedeutet im Umkehrschluss, dass Java Web Start auf allen Betriebssystemen zur Verfügung steht und verwendet werden kann, auf denen eine neuere Java-Laufzeitumgebung installiert ist. Gegebenenfalls installiert das Java-System bei Bedarf neuere Versionen von Web Start oder fehlende Bibliotheken beim Laden einer Web Start-Applikation nach. Das könnte neben den mittlerweile bedeutend schnelleren Internet-Verbindungen der Schlüssel für den Erfolg solcher modernen Java- und JavaFX-Applikationen sein, der Applets und dem Net-PC versagt blieb. Eine Java-Web-Start-Applikation wird auf einem Server zum Download bereitgestellt und beschreibt über eine spezielle XML-Datei mit der Dateierweiterung .jnlp die einzelnen Komponenten der Anwendung. Der anbietende Server muss zudem mit dem MIME-Type application/ x-java-jnlp-file umgehen können. Im Unterschied zu Java-Applets benötigen Java-Web-Start-Applikationen keinen Browser, sondern sie werden direkt in der normalen JVM eines Rechners ausgeführt (durchaus auch eine erweiterte JVM wie im Fall von JavaFX). Java Web Start wird auf einem Client mit installierter JRE automatisch gestartet, wenn eine JavaWeb-Start-Applikation zum ersten Mal aus dem Netz geladen wird. Die gesamte Anwendung wird anschließend lokal auf Ihrem Computer im Cache46 der Java-Web-Start-Technologie vorgehalten. Daher werden nachfolgende Startvorgänge fast so schnell wie der Start einer lokalen Applikation ausgeführt. Es sei denn, es gibt eine neue Version des Programms. Java Web Start überprüft bei jedem Start, ob auf dem bereitstellenden Server eine neue Version zur Verfügung steht. So kann man gewährleisten, dass ein Client immer die neueste Version einer Anwendung ausführt. Steht eine neue Version zur Verfügung, lädt das Programm sie automatisch herunter und startet sie. Das Starten einer Anwendung mithilfe von Java Web Start wird in der Regel über eine der nachfolgenden Arten erfolgen:
Aus einem Webbrowser heraus Über den Anwendungsmanager des Betriebssystems Über ein Desktopsymbol oder das Startmenü
45 Sie erinnern sich an das oben kurz angedeutete Konzept des Netz-PC? Auch hiermit hat Sun versucht, diese Idee eines Thin Clients auf Basis von Java zu etablieren. 46 Ein Cache ist erst einmal nur ein Speicherbereich, über den ein Zugriff auf Daten im Allgemeinen schneller möglich ist als von der Originalquelle. Bei einer Netzwerkverbindung ist ein Cache in der Regel ein Bereich auf einem lokalen Datenträger (ein Verzeichnis).
50
Der erste Kontakt
Abbildung 2.6: Web Start wird bei Bedarf vor dem Ausführen einer JavaFX-Applikation auf Stand gebracht 47
> >
>
HINWEIS
Der Begriff XML wurde im Laufe des Buchs schon einige Male peripher gestreift. Es ist die Abkürzung für eXtensible Markup Language. Dies beschreibt einen plattformneutralen Klartextstandard auf Unicode-Basis zur Erstellung maschinen- und menschenlesbarer Dokumente, um darüber beliebige Informationen auszutauschen. XML-Dokumente liegen in Form einer Baumstruktur vor, die eine Navigation zu den einzelnen Zweigen des Baums gestattet. XML ist wie HTML und XHTML eine Auszeichnungssprache (Markup Language), um über die Textinformation hinaus eine Struktur der Information zu bieten. Die in einem Dokument enthaltenen Informationen werden dazu durch Tags strukturiert, die auch in XML in spitze Klammen notiert werden. Die Elemente in XML sind im Gegensatz zu (X)HTML aber nicht vorgegeben. Es gibt keinen vorgefertigten, beschränkten Sprachschatz an Elementen. Im Gegensatz zu HTML, das auch über eine solche Semantik verfügt und neben jedem Tag auch dessen Bedeutung beschreibt, besteht XML lediglich aus einer Beschreibung der Syntax für Elemente und Strukturen. Damit ist XML freilich beliebig erweiterbar. Sie können Metainformationen über die Tags umsetzen. Die XML-Spezifikation beschreibt lediglich, nach welchen Regeln Sie Tags (oder besser Elemente) zu definieren haben. Die Festlegung von Tags machen Sie selbst47. Daher kann ein Leser oder Parser (zum Beispiel ein Webbrowser) die Bedeutung eines Elements aber auch nicht aus dem Kontext erschließen. Für die
47 Das bedeutet aber nicht, dass Sie in XML nicht Elemente definieren können, die denen von HTML entsprechen. Im Gegenteil – genau das werden Sie im Fall von AJAX wahrscheinlich öfter machen, um bei der Interpretation im Client ein Verhalten wie bei HTML-Elementen zu gewährleisten.
51
Kapitel 2 48
Interpretation eines XML-Dokuments müssen sämtliche relevanten Details spezifiziert werden. Dies betrifft insbesondere die Festlegung der Strukturelemente und ihre Anordnung innerhalb des Dokumentenbaums48. Im Gegensatz zu HTML ist XML syntaktisch eine sehr strenge Sprache, bei der es kein Prinzip der Fehlertoleranz gibt. Die XML-Spezifikation ist streng formal und lässt keine Ausnahmen und unklaren Strukturen zu. Dadurch ist XML jedoch einfach und automatisiert zu validieren. XML beschreibt nur wenige, einfache, aber eben sehr strenge und absolut eindeutige Regeln, nach denen ein Dokument zusammengesetzt sein kann.
> >
>
HINWEIS
Das Java Network Launching Protocol (JNLP) ist ein spezielles XML-Format zur Festlegung, wie Java-Web-Start-Anwendungen aufgerufen werden. JNLP-Dateien enthalten Informationen wie den konkreten Speicherort von .jar-Dateien und anderen Ressourcen, die die Applikation verwendet, den Namen der Hauptklasse einer Anwendung und zusätzliche Parameter für das aufzurufende Programm. Den genauen Aufbau einer solchen Datei (einer so genannten Launch-Datei) werden wir in Kapitel 6 besprechen.
> >
>
HINWEIS
JAR steht für Java Archive und bezeichnet eine zum .zip-Format binärkompatible Datei, die zusätzliche Metadaten enthält. Java Archive werden vor allem zur Verteilung von Java-Klassenbibliotheken und -Programmen als auch JavaFX-Applikationen eingesetzt, können aber auch universeller verwendet werden.
> >
>
HINWEIS
MIME steht für Multipurpose Internet Mail Extensions und bedeutet einen Internet-Standard zur Spezifizierung von Dateitypen bei der Kommunikation zwischen einem Server und einem Client. Der Aufbau von MIME-Typen ist immer gleich und wird nach folgendem Schema angegeben: Hauptkategorie/Unterkategorie Listing 2.6: Das Schema eines MIME-Typs
Nachdem nun eine ganze Reihe an neuen Begriffen eingeführt wurde, wenden wir uns wieder JavaFXPad zu.
48 XML kann auf diese Weise zur Definition beliebiger eigener Sprachen verwendet werden. Es ist eine so genannte Metasprache zur Definition von beliebigen, in ihrer Grundstruktur jedoch stark verwandten Auszeichnungssprachen.
52
Der erste Kontakt
2.4.2 JavaFXPad starten Wie oben besprochen, gibt es verschiedene Möglichkeiten um eine Java-Web-Start-Applikation aufzurufen. Sie können beispielsweise einen URL zu Applikation direkt in die Adresszeile des Browsers eingeben oder auf einen entsprechenden Link in einer bereitgestellten Webseite des Anbieters der Java-Web-Start-Applikation klicken. Für JavaFXPad verwenden Sie den URL http://download.java.net/general/openjfx/demos/javafxpad.jnlp. TIPP
Alternativ können Sie die Java-Web-Start-Applikation auch direkt über die Kommandozeile oder den AUSFÜHREN-Befehl von Windows oder Linux über die folgende Syntax aufrufen: javaws http://download.java.net/general/openjfx/demos/javafxpad.jnlp Dieser Aufruf lässt sich natürlich auch mit einem Symbol auf dem Desktop verknüpfen oder in das Startmenü eintragen.
Wenn Sie den angegebenen URL über einen Browser aufrufen, bietet Ihnen der Browser in der Regel die Möglichkeit an, die Datei zu speichern. Aber dieses wollen wir nicht tun, sondern die .jnlp-Datei mit Java Web Starter Launch direkt aus dem Browser heraus ausführen49. Auch diese Möglichkeit sollte Ihnen der Browser als Alternative zur Verfügung stellen.
Abbildung 2.7: Ausführen der Java-Web-Start-Applikation direkt aus einem Browser heraus
49 So etwas steht wie gesagt unter jedem Betriebssystem zur Verfügung, wenn eine neuere Java-Version installiert ist.
53
Kapitel 2
Sollten Sie planen, häufiger Web-Start-Applikationen auszuführen, können Sie den Browser auch veranlassen, für Dateien des Typs .jnlp immer diese Aktion auszuführen. Da Sie in diesem Fall allerdings eine fremde Applikation direkt aus dem Internet starten, sollten Sie natürlich Ihre Firewall und Ihre Sicherheitseinstellung im Browser oder sogar dem Betriebssystem erst einmal warnen50. Für diese Applikationen müssen Sie die Ausführung gestatten, sonst können Sie nicht mit JavaFXPad arbeiten (und natürlich gilt das für alle weiteren Web-Start-Applikationen, die Sie in Zukunft einsetzen wollen).
Abbildung 2.8: Hoffentlich werden Sie gewarnt – aber in diesem Fall sollten Sie die Applikation dennoch ausführen
> >
>
HINWEIS
Die Technik des Java Web Start eignet sich auch ideal, wenn Sie Ihre eigenen JavaFX-Applikationen zu Verfügung stellen wollen. Darauf werden wir in Kapitel 6 noch genau eingehen.
Wenn Sie diese Applikation nun über das Internet gestartet haben, erhalten Sie in der Grundeinstellung eine geteilte Entwicklungsumgebung für JavaFX. Diese unterteilt sich in ein oben angesiedeltes Vorschaufenster für Ihre JavaFX-Applikation (ein so genanntes Canvas-Fenster) und einen einfachen Texteditor, der darunter angezeigt wird. Das Zusammenspiel zwischen diesen beiden Bestandteilen der Entwicklungsumgebung ist unmittelbar. Das bedeutet, wenn Sie im Editorbereich Quellcode notieren oder verändern, zeigt das Fenster darüber unmittelbar das interpretierte Resultat. Ganz unten sehen Sie ein Statusfenster, in dem gegebenenfalls Fehlermeldungen oder andere Meldungen des Systems beim Ausführen der Applikation angezeigt werden. 50 Sollten Sie keine Warnmeldung bekommen, würde ich mir massive Gedanken um das Sicherheitskonzept des Rechners machen!
54
Der erste Kontakt
> >
>
HINWEIS
Ich denke, es ist bereits jetzt offensichtlich, dass diese Arbeit mit JavaFXPad ein sehr viel einfacherer und schnellerer Weg ist, mit JavaFX zu experimentieren, als wenn Sie mit einem primitiven Texteditor und über die Konsolenebene arbeiten.
Beim ersten Start von JavaFXPad sehen Sie unmittelbar einen Beispielquellcode, der in der Applikation angezeigt wird.
Abbildung 2.9: Der JavaFXPad-Editor mit einer Beispielapplikation
Wenn nun JavaFXPad bei Ihnen läuft, können Sie Ihre ersten Experimente starten, um den Umgang mit dem Tool zu lernen als auch Ihre ersten Erfahrungen mit JavaFX Script ein wenig zu vertiefen.
55
Kapitel 2
2.4.3 Die Beispielapplikation manipulieren Um den Umgang mit JavaFXPad zu üben, werden wir zu Beginn einfach das vorgegebene Listing manipulieren. Da der Quellcode relativ umfangreich und sowieso für alle Leser nach dem ersten Start der Applikation identisch ist, wird aus Platzgründen auf das Abdrucken hier verzichtet.
> >
>
HINWEIS
Eine Zeilennummerierung wird von JavaFXPad zur Verfügung gestellt, so dass sich in diesem Fall die folgenden Angaben der Zeilennummer für eine Änderung in Quellcode auf die Nummerierung des Originalquellcodes in JavaFXPad beziehen.
Betrachten wir zuerst, welche Features uns JavaFXPad zur Verfügung stellt. Diese werden Ihnen später auch in mächtigeren Entwicklungstools begegnen.
Syntax Highlighting Wenn Sie sich den Editorbereich von JavaFXPad betrachten, erkennen Sie, dass dieser bereits eine grundlegende Formatierung verschiedener Syntaxstrukturen vornimmt. Sowohl durch farbliche Unterscheidung von Syntaxstrukturen als auch Formatierungen wie fett oder kursiv. Man spricht hier von so genanntem Syntax Highlighting. Dieses Feature erleichtert insbesondere Einsteigern in einer Programmier- oder Skriptsprache wie JavaFX Script den Umgang mit der Syntax erheblich. Ändern Sie einmal die Zeile 7. Hier sollte in der Originalversion Folgendes zu sehen sein: var x = 0 Listing 2.7: Die Zeile 7 des Beispiels in der Originalversion
Die Änderung soll wie folgt ausfallen: Var x = 0 Listing 2.8: Die Zeile 7 des Beispiels in der Originalversion
Sie werden sofort sehen, dass das Wort Var farblich anders dargestellt wird als var. Ebenso wird es nicht mehr fett formatiert. In der Schreibweise var handelt es sich um ein Schlüsselwort von JavaFX Script, in der Schreibweise Var nicht51. Über Syntax Highlighting werden diese Quellcodestrukturen unterschiedlich dargestellt, was das Erkennen eines Fehlers beispielsweise erheblich erleichtert.
51 Es wurde schon angedeutet, dass Groß- und Kleinschreibung in JavaFX Script eine Rolle spielt.
56
Der erste Kontakt
> >
>
HINWEIS
Ein Schlüsselwort ist ein integraler Bestandteil einer Programmier- oder Skriptsprache mit einer festen Bedeutung.
> >
>
HINWEIS
Wenn Sie in der Zeile 7 Var statt var notieren, erkennen Sie übrigens auch im unteren Fenster in JavaFXPad eine Fehlermeldung. Dieser Fehler wird ebenso durch die rote Schlangenlinie markiert. Das ist aber nicht unbedingt die Stelle, wo Sie den Fehler machen, sondern die Stelle, wo sich ein Fehler auswirkt.
Abbildung 2.10: In Zeile 7 sehen Sie, dass Var anders als var formatiert wird – ebenso erkennen Sie Fehlerhinweise
Korrigieren Sie nun den Fehler in Zeile 7 und stellen Sie die Originalversion wieder her.
Anpassung der Beispiels Wenn Sie im Vorschaufenster genau hinschauen, erkennen Sie einen Text, der auch irgendwo im Quelltext vorhanden sein muss. Sie finden ihn in der Originalversion des Quellcodes in Zeile 151: content: 'JavaFX' Listing 2.9: Die Zeile 151
Dies ist eine so genannte Zuweisung. Ändern Sie für den Augenblick nur den Text innerhalb der Hochkommata. Zum Beispiel in www.rjs.de. content: 'www.rjs.de' Listing 2.10: Die geänderte Zeile 151
57
Kapitel 2
Sie sehen im Vorschaufenster unmittelbar das Resultat.
Abbildung 2.11: Das geänderte Beispiel
Ziemlich deutlich ist der geänderte Text zu sehen. Aber genauso deutlich ist, dass der Text so nicht in den Rahmen passt, in den der vorherige Text gepasst hat. Der neue Text ragt über den Rand hinaus. Nun können wir für eine Korrektur entweder den Rahmen vergrößern oder die Schriftgröße verkleinern. Bisher haben wir uns noch nicht mit JavaFX Script auseinander gesetzt und ich möchte auch wie gesagt keine Java-Kenntnisse bei Ihnen voraussetzen. Aber es sollte dennoch ein leichtes Spiel sein, in der Zeile 152 die Schriftgröße zu erkennen. Das ist der Wert 25.0. Machen wir daraus die Schriftgröße 15.0. Ändern Sie diese Zeile wie folgt: font: Font {faceName: 'Verdana', style: BOLD, size: 15.0} Listing 2.11: Die geänderte Zeile 152
58
Der erste Kontakt
Sie erkennen unmittelbar in der Vorschau, dass der Text nun in den vorgegebenen Rahmen passt.
Abbildung 2.12: Jetzt passt der Text in den Rahmen
Laden und Speichern sowie Ausführen Obwohl JavaFXPad direkt über das Internet gestartet wird, stellt das Tool natürlich Befehle zum Speichern und Öffnen von Dateien zur Verfügung. Diese finden Sie wie üblich unter dem Menüeintrag FILE. Auch das manuelle Ausführen einer JavaFX-Applikation finden Sie als Menüeintrag (RUN), obwohl in der Voreinstellung eine automatische Ausführung aktiviert ist. Sonst bietet das Tool aber wenige weitere Features.
Codevervollständigung Aber ein Feature muss noch erwähnt werden! JavaFXPad stellt eine Codevervollständigung für JavaFX Script zu Verfügung. Auch dies erleichtert insbesondere Einsteigern in JavaFX Script den Umgang mit der Syntax erheblich, aber auch Profis werden es
59
Kapitel 2
schätzen. Wenn Sie im Editor die Tastenkombination (STRG) + (Leerzeichen) drücken, aktivieren Sie die Codevervollständigung. An der Cursorstelle öffnet sich ein Popup mit einer Auswahlliste an übereinstimmenden Vervollständigungsmöglichkeiten, die an dieser Stelle im Quellcode Sinn machen könnten. Diese können Sie mit der Maus anklicken und in den Quellcode übernehmen.
Abbildung 2.13: Codevervollständigung
TIPP
Wenn Sie bereits einige Buchstaben geschrieben haben und der Cursor unmittelbar hinter diesen Zeichen steht, werden in der Auswahlliste nur noch die Begriffe angezeigt, die am Anfang mit den eingegebenen Zeichen übereinstimmen.
2.4.4 Eigene Beispiele mit JavaFXPad Vertiefen wir unsere ersten Erfahrungen mit der Welt von JavaFX mit zwei eigenen Beispielen, die wir mit JavaFXPad erstellen. Geben Sie den nachfolgenden Code im Editorfenster von JavaFXPad ein (JavaFXPad1.fx): 01 import javafx.ui.Label; 02 03 Label { 04 text: "JavaFX" 05 } Listing 2.12: Ein ganz primitives Beispiel
60
Der erste Kontakt
Sie sehen oberhalb des Editorbereichs – also im Vorschaufenster – sofort nach der Eingabe des Quellcodes den Text JavaFX. Dies wird über ein so genanntes Label (eine Anzeigemöglichkeit von Text – etwa für eine Beschriftung) erreicht. Speichern Sie das Listing unter JavaFXPad1.fx.
Abbildung 2.14: Das einfache Beispiel JavaFXPad1
So ist das Beispiel zwar in der Tat bereits eine vollständige JavaFX-Applikation, allerdings zugegeben wenig eindrucksvoll. Aber das kann man ändern. Die JavaFX-Umgebung implementiert sämtliche visuellen Swing-Komponenten aus der normalen Java-Bibliothek. Damit sind Sie beispielsweise für die Gestaltung Ihrer Oberfläche nicht auf ein einfaches Label beschränkt.
> >
>
HINWEIS
Unter Swing versteht man ein Teil des Java-APIs, das zu Gestaltung von grafischen Benutzeroberflächen dient. Darauf gehen wir natürlich noch genauer ein – konkret in Kapitel 5.
61
Kapitel 2
Sie können jede Form eines Widgets verwenden, das auch sonst in einer GUI (Graphical User Interface – auf deutsch Grafische Benutzeroberfläche) vorkommt. Etwa Schaltflächen, Dialoge, Auswahllisten, Baumstruktur etc.
> >
>
HINWEIS
Ein Widget (manchmal auch Gadget genannt) bezeichnet allgemein einen eigenständigen Teil einer grafischen Oberfläche, welches eine spezielle (meist kleine) Funktion oder Anzeige als Teil eines übergeordneten Konzepts der grafischen Oberfläche übernimmt. Etwa eben eine Schaltfläche. Manche Widgets dienen auch der Aufnahme anderer Widgets – beispielsweise so genannte Panels.
Das nachfolgende Beispiel JavaFXPad2.fx zeigt neben der Verwendung einer Schaltfläche auch gleich, wie man eine Reaktion auf einen Klick auf die Schaltfläche in JavaFX umsetzen kann. Erstellen Sie das nachfolgende Beispiel. 01 02 03 04 05 06 07 08 09 10 11 12 13
Listing 2.13: Eine JavaFX-Applikation mit Schaltfläche und der Behandlung der Reaktion
Zuerst sehen Sie im Vorschaufenster von JavaFXPad nur eine Schaltfläche (Button) mit der angegebenen Beschriftung (text). Wenn Sie diese anklicken, öffnet sich ein Mitteilungsfenster (MessageDialog). Dieses hat eine Titelzeile (title), deren Beschriftung in dem Listing ebenso zu sehen ist, sowie einen Text, der über die Eigenschaft message spezifiziert wird.
62
Der erste Kontakt
Abbildung 2.15: Nach dem Klick auf die Schaltfläche wird ein Mitteilungsfenster angezeigt
2.5 JavaFX mit Eclipse Obwohl es nicht sonderlich schwer war, mithilfe eines reinen Texteditors und der JavaFX Shell das erste Beispiel zu erstellen und auszuführen, dürfte es wie gesagt offensichtlich sein, dass dieser Weg nicht sonderlich bequem ist. Bereits der Einsatz von JavaFXPad war eine erhebliche Erleichterung. Aber obwohl JavaFXPad schon recht bequem und vor allem einfach zu bedienen ist, ist auch dieses Tool eigentlich nur für den Einstieg in JavaFX ideal. Wenn man wirklich effektiv mit JavaFX in der Praxis programmieren möchte, führt kein Weg um eine vollständige integrierte Entwicklungsumgebung herum. Wie bereits angedeutet, konzentrieren wir uns in diesem Buch dazu auf Eclipse beziehungsweise hauptsächlich auf eine IDE mit Namen NetBeans.
63
Kapitel 2
TIPP
Selbstverständlich können Sie die gleichen JavaFX-Dateien mit verschiedenen Editoren bzw. IDEs verarbeiten.
Beide IDEs müssen aber zuerst natürlich geladen bzw. installiert werden und dann beide noch in den Versionen, die dem Buch zugrunde liegen, ein bisschen erweitert werden, damit Sie damit JavaFX-Applikationen erzeugen und integriert ausführen können. Das macht man in beiden Fällen mit einem so genannten PlugIn.
> >
>
HINWEIS
Unter einem PlugIn versteht man allgemein eine Erweiterung eines Programms.
Betrachten wir zuerst, wie Sie das JavaFX Script PlugIn für Eclipse verwenden können. Aber dazu soll ein kurzer Exkurs über Eclipse vorangestellt werden.
2.5.1 Was ist Eclipse? Da die Zielgruppe von diesem Buch explizit auch Leser umfasst, die bisher nur wenig programmiert bzw. insbesondere noch nicht viel mit Java gearbeitet haben, ist es durchaus wahrscheinlich, dass mehrere Leser nicht wissen, was Eclipse ist. Deshalb soll kurz erklärt werden, was sich dahinter verbirgt. Bei Eclipse handelt es sich um ein Open-Source-Programm zur Programmierung, das ursprünglich jedoch von einer Firma – IBM – entwickelt und erst später freigegeben wurde. Eclipse ist nicht nur ein Editor, sondern eine extrem mächtige und leistungsfähige IDE, die es für verschiedene Betriebssysteme gibt. Obwohl Eclipse selbst in Java geschrieben52 und im Schwerpunkt auf die Entwicklung mit Java ausgerichtet ist, können in Eclipse mithilfe unzähliger PlugIns nahezu alle Programmiertechniken abgedeckt werden. Allerdings ist Eclipse durch die Mächtigkeit nicht ganz einfach im Umgang und die Hardware muss auch entsprechend gut bei Kräften sein.
2.5.2 Download und Installation von Eclipse Eclipse finden Sie beispielsweise unter http://www.eclipse.org kostenlos zum Download. Die Installation von Eclipse ist vollkommen unproblematisch, wenn auf einem Rechner bereits ein neueres JDK installiert ist (was bei uns für die Arbeit mit JavaFX ja sowieso der Fall ist). Eclipse wird als komprimierte Datei ausgeliefert, die wir einfach extrahieren müssen. Beim ersten Start sucht sich die IDE die passende Java-Umgebung und richtet das System weitgehend automatisch ein. 52 Deshalb brauchen Sie zur Ausführung auch ein JDK.
64
Der erste Kontakt
2.5.3 Das JavaFX Script PlugIn für Eclipse Eclipse beinhaltet allerdings wie gesagt derzeit in der Grundeinstellung noch keine Unterstützung für JavaFX, was aber über das ausgefeilte Verfahren nach Installation von PlugIns überhaupt kein Problem ist. Ein JavaFX Script PlugIn (oder kurz JavaFX PlugIn) kann für Eclipse ab der Version 3.2.2 wie folgt nachinstalliert werden. Zuerst starten Sie Eclipse. Im Hauptmenü wählen Sie HELP / SOFTWARE UPDATES / FIND AND INSTALL. Hierüber kommen Sie zu dem integrierten Softwareverwaltungsmechanismus von Eclipse, über den Sie direkt aus Eclipse heraus beliebige PlugIns nachinstallieren können, wenn diese über das Internet bereitgestellt werden. Ebenso können Sie hier Eclipse selbst sowie bereits installierte PlugIns aktualisieren. Im folgenden Install/Update-Dialog wählen Sie SEARCH FOR NEW FEATURES TO INSTALL und klicken dann auf NEXT. Dann wählen Sie als Anweisung NEW REMOTE SITE. Im folgenden Dialog New Update Site müssen Sie einen Namen für die neue zu installierende Komponente vergeben. Der Name ist vollkommen frei, sollte aber sprechend sein, damit Sie bei späteren Aktualisierungen die Komponente zuordnen können. Für unser PlugIn wählen wir JavaFX. In das URL-Feld geben Sie die folgende Adresse ein53: http://download.java.net/general/openjfx/plugins/eclipse/site.xml
Abbildung 2.16: Die Angabe einer neuen Seite zur Installation beziehungsweise eines Updates eines PlugIns
Wenn Sie die Angaben bestätigen, erscheint der eigentliche Updates-Dialog.
53 Sie sollten die Adresse aber gegebenenfalls überprüfen. Sie kann sich selbstverständlich über die Zeit ändern.
65
Kapitel 2
Abbildung 2.17: Der Updates-Dialog – hier unter der Linux-Variante von Eclipse
Dieser kann sich je nach System optisch etwas unterscheiden, aber Sie sollten in jedem Fall einfach einen Haken an den JavaFX-Knoten setzen und auf NEXT klicken. Im Folgedialog bestätigen Sie, welche Features tatsächlich installiert werden.
Abbildung 2.18: Die genaue Angabe, was installiert wird
66
Der erste Kontakt
Nach der Bestätigung der Lizenzbedingungen und dem Abschluss der Installation können Sie nach einem Neustart von Eclipse das neue PlugIn verwenden und mit Eclipse eine JavaFX-Applikation erstellen. Testen wir, ob das nun wirklich funktioniert.
2.5.4 Eine JavaFX-Applikation mit Eclipse erstellen Die Arbeit mit Eclipse basiert darauf, dass Sie grundsätzlich Ihre Beispiele in Projekten organisieren. Und ein solches Projekt muss erst einmal angelegt werden. Dazu gehen Sie wie folgt vor.
Erstellen eines Projekts Wenn Eclipse gestartet ist, erstellen Sie zuerst ein neues Projekt. Dazu wählen Sie zum Beispiel FILE -> NEW -> PROJECT.
Abbildung 2.19: Erstellen eines neuen Eclipse-Projekts
Wählen Sie im folgenden Dialog ein Java-Projekt aus.
Abbildung 2.20: Anlegen eines neuen Java-Projekts
67
Kapitel 2
Nennen Sie es JFX1 und lassen Sie ansonsten alle Vorgaben, wie sie sind.
Abbildung 2.21: Festlegung des Namens für ein Projekt
Im nächsten Schritt wählen Sie wiederden Menüpunkt FILE -> NEW. Nur dieses Mal wählen Sie dort kein Projekt aus, sondern den Untereintrag OTHER.... Im folgenden Schritt des Assistenten erhalten Sie die Möglichkeit, in dem aktuellen Projekt verschiedene Arten an Dateien anzulegen. Sie sollten in dem angezeigten Baum eine Kategorie JavaFX finden. Diese wurde bei der Installation des PlugIns angelegt. Dort wählen Sie JAVAFX FILE aus.
68
Der erste Kontakt
Abbildung 2.22: Die Erstellung einer JavaFX Script-Datei verbirgt sich hinter Other...
Abbildung 2.23: Auswahl einer JavaFX-Datei
Der Einfachheit halber behalten wir in dem nun folgenden Dialog den Vorgabenamen File1.fx für die neu zu erzeugende Datei bei.
69
Kapitel 2
Sie sehen nach der Bestätigung in Eclipse einen Editorbereich, in dem Sie den Quelltext für JavaFX-Applikation eingeben können.
Abbildung 2.24: Eine JavaFX-Applikation in Eclipse erstellen
> >
>
HINWEIS
Eclipse verfügt für die Erstellung von JavaFX-Code wie JavaFXPad im Rahmen des PlugIns natürlich über Syntax Highlighting und Codevervollständigung. Darüber hinaus stehen einige Features zu Verfügung, die Eclipse sowieso bereitstellt. Dennoch ist das PlugIn in der Version, die dem Buch zu Grunde liegt, noch nicht so leistungsfähig und ausgereift, wie man es von Eclipse und anderen PlugIns für diese IDE gewohnt ist. Aber es steht zu erwarten, dass auch dieses JavaFX PlugIn wie auch JavaFX selbst in kurzer Zeit erheblich weiterentwickelt und in der Qualität als auch dem Funktionsumfang gesteigert werden.
Wenn Sie eine Applikation nun in Eclipse erzeugt haben, führen Sie diese über den Befehl RUN aus. Sie müssen allerdings in dem folgenden Dialog angeben, dass Sie die Konfiguration für eine JavaFX-Applikation ausführen wollen. Dazu müssen das richtige Projekt und als Main Class die FXShell (das ist eine Klasse in der Erweiterungsbibliothek – net.java.javafx.FXShell) selektiert sein.
70
Der erste Kontakt
Abbildung 2.25: Ausführen der Applikation über Eclipse
Im Registerblatt Arguments müssen Sie nun noch eine Launch-Datei für Ihr Projekt angeben. Diese Datei müssen Sie in der aktuellen Version des JavaFX-PlugIns von Eclipse gegebenenfalls noch manuell erstellen, was recht unbefriedigend ist. In NetBeans wird das automatisch gemacht. Es steht aber zu hoffen, dass dies auch in späteren Versionen des JavaFX-PlugIns für Eclipse eingeführt wird. Damit es an dieser Stelle nicht ausufert, sollten Sie zum Start einfach auf die besprochene Batch- bzw. ShellDatei zurückgreifen, wenn auch in der Ihnen vorliegenden Version noch keine LaunchDatei erzeugt wird.
> >
>
HINWEIS
Wie genau so eine Launch-Datei aussieht, werden wir in Kapitel 6 genauer behandeln.
71
Kapitel 2
2.6 JavaFX mit NetBeans Eine weitere Java-IDE, mit der Sie JavaFX-Applikationen erstellen und ausführen können, ist wie schon erwähnt NetBeans ab der Version 5. Oder man sollte es etwas schärfer formulieren: derzeit ist es die ideale IDE für JavaFX-Applikationen. Warum das? Lassen Sie uns dazu erst einmal klären, was sich hinter NetBeans verbirgt.
2.6.1 Was ist NetBeans? Aufbauend auf dem JDK gab und gibt es zahlreiche Java-Entwicklungsumgebungen. Teils sehr einfache, teils mächtigere Tools. Teilweise waren und sind die Tools kostenlos, teilweise aber auch kostenpflichtig (oft sind die sehr leistungsfähigen Tools sogar sehr teuer). Mit dem Auftauchen des kostenlosen Eclipse wurde der Markt der JavaEntwicklungsumgebungen gewaltig umstrukturiert. Eclipse ist ein dermaßen mächtiges Tool54, dass sowohl der Markt für kostenpflichtige Java-Entwicklungsumgebungen sehr klein wurde als auch vielen kostenlosen Alternativen die Entwickler weggelaufen sind55. Aber es gibt im Java-Umfeld natürlich immer noch Entwicklungstools jenseits von Eclipse. Eine dieser kostenlosen Alternativen zu Eclipse ist NetBeans. Wie Eclipse ist auch NetBeans selbst in Java geschrieben und verfügt über übliche Features wie Syntax Highlighting und Codevervollständigung. Und wie Eclipse kann man mit NetBeans nicht nur Java-Programme schreiben (obwohl es auch bei NetBeans ganz klar der Schwerpunkt ist), sondern es werden mittlerweile auch diverse andere Sprachen wie C, C++, Ruby und Fortran unterstützt. Und noch eine Gemeinsamkeit zu Eclipse ist der vollständig modulare Aufbau, der durch PlugIns erweitert werden kann. Aber warum wählen wir genau diese Alternative zu dem Eclipse-Platzhirsch für die weitere Arbeit mit JavaFX in dem Buch aus? Na ja – wer stellt NetBeans zu Verfügung? Sun! Es handelt sich hier um die eigene IDE zur Entwicklung von Java-Applikation des Erfinders von Java und JavaFX. Und nicht zuletzt deswegen ist NetBeans nicht nur eine hervorragende Java-IDE, sondern das JavaFX-PlugIn für NetBeans beziehungsweise die allgemeine Unterstützung von JavaFX ist in diesem Tool natürlich hervorragend. Eine solche nahtlose Integration kann derzeit nur Sun durch sein Know-how bezüglich Java und JavaFX gewährleisten. Und man sollte auch bei aller Popularität von Eclipse nicht vergessen, dass viele Konzepte, die dort umgesetzt werden, ursprünglich in NetBeans ihren ersten Einsatz gefunden hatten.
54 Das zudem noch kompatibel zur kostenpflichtigen Erweiterung beziehungsweise Tools von IBM ist. 55 Ich bin selbst großer Fan von Eclipse.
72
Der erste Kontakt
2.6.2 Download und Installation von NetBeans NetBeans wird Ihnen von Sun in verschiedenen Versionen und für verschiedene Betriebssysteme kostenlos zum Download zur Verfügung gestellt. Wir beziehen uns in dem Buch auf die Version 6 und diese finden Sie unter http://bits.NetBeans.org/download/ 6.0/milestones/latest/.
Abbildung 2.26: Download von NetBeans
Die Installation von NetBeans ist wie bei Eclipse vollkommen unproblematisch. Es muss nur auf dem Rechner bereits ein neueres JDK installiert sein. Dann führt ein klassischer Installationsassistent zum Erfolg.
73
Kapitel 2
Abbildung 2.27: NetBeans wird mit einem typischen Installer problemlos installiert
2.6.3 Das JavaFX Script PlugIn für NetBeans Auch NetBeans beinhaltet wie Eclipse derzeit in der Grundeinstellung noch keine direkte Unterstützung für JavaFX. Auch hier installieren wir dazu ein JavaFX Script PlugIn nach, wobei wir uns in den nachfolgenden Ausführungen und Screenshots explizit auf die NetBeans IDE 6.0 Preview (Milestone 9 oder neuer) unter Windows XP beziehen. Bei anderen Konstellationen kann der Vorgang sich in kleineren Details unterscheiden, aber im Wesentlichen läuft er identisch ab und die Unterschiede sollten keine Rolle für die Programmierung spielen.
74
Der erste Kontakt
Zuerst starten Sie jetzt NetBeans. Ein JavaFX Script PlugIn kann dann über das integrierte Development Update Center geladen und installiert werden. Im Hauptmenü wählen Sie dazu TOOLS -> PLUGINS56. Es öffnet sich der PlugIn Manager von NetBeans.
Abbildung 2.28: Das Fenster vom PlugIn Manager
In dem Fenster des PlugIn Manager wählen Sie das Register SETTINGS und dort fügen Sie über ADD das JavaFX PlugIn hinzu. In dem nun folgenden Dialogfenster geben Sie einen Namen für den Service an. Wichtig ist wie beim PlugIn in Eclipse der URL. Dort tragen Sie entweder http://www.NetBeans.org/updates/60m9_1.18_.xml für die Version Milestone 9 Preview oder http://www.NetBeans.org/updates/60m10_1.22_.xml oder http:// www.netbeans.org/updates/beta/60_1.24_.xml.gz für die Version Milestone 10 Preview ein. Sollte es neuere Versionen geben, werden Sie den URL leicht im Internet recherchieren können, was Sie natürlich auch machen sollten – es ist in jedem Fall sinnvoll, mit der neuesten Version des PlugIns zu arbeiten. Nun wählen Sie das Register NEW PLUGINS bzw. AVAILABLE PLUGINS57, aktualisieren die Liste und klicken die Checkbox für das JavaFX-Plugin an.
56 Bzw. NETBEANS -> PLUGINS auf einer Mac OS X-Plattform. 57 Das kann sich je nach konkreter Version von NetBeans unterscheiden.
75
Kapitel 2
Abbildung 2.29: Angabe des URL für die Installation des Plugins
Abbildung 2.30: Das JavaFX-Plugin mit seinen Komponenten wird installiert
76
Der erste Kontakt
Klicken Sie dann auf die Schaltfläche INSTALL. Mit einem folgenden einfachen Assistenten werden Sie zum Ende der Installation geführt. Im Register INSTALLED sehen Sie dann nach dem erfolgreichen Abschluss des Assistenten, dass nun das JavaFX-Plugin installiert ist. Dieses besteht aus den einzelnen Modulen JavaFX Project, JavaFX Editor, JavaFX UserLibrary und JavaFX Library.
Abbildung 2.31: Das JavaFX-Plugin ist in NetBeans installiert
> >
>
HINWEIS
Auch das Plugin für NetBeans liegt zum Zeitpunkt der Bucherstellung in einer frühen Version vor. Zum Teil reagiert NetBeans bei der Erstellung von JavaFX-Applikationen sehr »Java-lastig«. Das bedeutet, gewisse automatische Hilfen passen zwar zu Java, aber nicht JavaFX. Aber auch bei diesem Plugin steht zu erwarten, dass es in kurzer Zeit weiterentwickelt wird.
2.6.4 Eine JavaFX-Applikation mit NetBeans erstellen Sobald Sie das Plugin in NetBeans installiert haben, können Sie JavaFX Script-Dateien mit der IDE erstellen, modifizieren und ausführen. Und das gehen wir jetzt an. Wir erstellen die Grundstruktur für eine JavaFX-Applikation mit NetBeans.
Ein neues Projekt in NetBeans Wie auch Eclipse organisiert NetBeans Quellcodes in Projekten. Also müssen wir zuerst ein neues Projekt aufsetzen. Wenn NetBeans gestartet ist, erstellen Sie ein neues Projekt über den Eintrag FILE -> NEW PROJECT aus dem Hauptmenü. Im folgenden New
77
Kapitel 2
Project-Wizard finden Sie eine Aufstellung von Kategorien, welche Art von Projekten NetBeans in der aktuellen Konfiguration unterstützt. Sie selektieren hier natürlich JAVAFX. Auf der rechten Seite wählen Sie bei dem Projekttypen JAVA FX APPLICATION.
Abbildung 2.32: Ein neues JavaFX-Projekt in NetBeans
Im nächsten Schritt vergeben Sie einen Projektnamen (z. B. JavaFXapp1) und legen bei Bedarf fest, wo das Projekt gespeichert wird. Die restlichen Einstellungen können Sie so lassen, wie sie vorgeschlagen werden. Nach dem Klick auf die Schaltfläche FINISH werden das JavaFXapp1-Projekt und eine Main.fx-Quellcodedatei erstellt und im Projektfenster von NetBeans angezeigt. Zusätzlich wird der Inhalt der Datei Main.fx im Quellcodeeditor angezeigt.
78
Der erste Kontakt
Abbildung 2.33: Der Name und Ort des Projekts
Abbildung 2.34: Das JavaFX-Projekt bei Beginn
79
Kapitel 2
Erstellen eines JavaFX-Programms Das Erstellen des eigentlichen Programms erfolgt nun einfach über die Modifizierung der Datei Main.fx. Notieren Sie darin das folgende Listing, wobei die eventuell notwendige package-Anweisung hier nicht angegeben wird (sie muss aber erhalten bleiben, wenn sie bei Ihnen generiert wurde): 01 02 03 04 05 06 07 08 09 10 11 12 13 14
Dieses Beispiel kennen wir im Wesentlichen. Aber auch an dieser Stelle verschieben wir die Erklärungen zu den Details. Wir wollen hier einfach den Umgang mit NetBeans zeigen.
Ein JavaFX-Programm in NetBeans ausführen Im Projektfenster von NetBeans klicken Sie zum Ausführen der Applikation am einfachsten mit der rechten Maustaste auf den JavaFXapp1-Knoten und selektieren da RUN PROJECT.
Abbildung 2.35: Ausführen einer JavaFX-Applikation
80
Der erste Kontakt
Der Befehl übersetzt die Applikation automatisch und führt sie aus. Wenn Sie unsere Beispielapplikation ausführen, sehen Sie ein kleines Fenster mit einer Schaltfläche.
Abbildung 2.36: Die laufende Applikation
Wenn Sie auf die Schaltfläche klicken, wird das Programm beendet.
> >
>
HINWEIS
Es gibt zwei Wege, wie Sie Skripte aus der NetBeans-IDE ausführen können. Sie verwenden die Klasse net.java.javafx.FXShell, die wir ebenfalls in Eclipse schon einmal gesehen haben, oder den eingebauten Script-Engine-Support von Java SE 6. Das IDE-Plugin setzt die Hauptklasse eines Projekts auf die FXShell, der Sie den vollqualifizierten Skriptnamen als Argument übergeben. In NetBeans können Sie das über die Projekteigenschaften konfigurieren.
Den Befehl zum Ausführen einer JavaFX-Applikation finden Sie auch im normalen Menü unter RUN. Unter dem Menüpunkt BUILD können Sie die JavaFX-Applikation übersetzen, ohne sie auszuführen.
81
3
Das Syntaxkonzept von JavaFX Script
Sie haben nun alle Voraussetzungen zur Erstellung und Ausführung von JavaFX-Applikationen geschaffen und auch schon erste Beispiele gesehen. Bezüglich der Syntax und des Konzeptes von JavaFX sollten aber bei diesen ersten Beispielen zahlreiche Fragen offen geblieben sein. In diesem Kapitel gehen wir nun genauer auf das syntaktische Konzept von JavaFX als Skriptsprache ein. JavaFX Script bezeichnet eine so genannte deklarative und statisch typisierte Programmiersprache respektive Skriptsprache58. Es gibt in einer solchen Sprache z. B. Techniken wie Funktionen, Klassen, Deklarationen, inkrementelle Evaluierung etc. Aber JavaFX Script hat zudem einige Besonderheiten aufzuweisen. Mit dieser neuen Skriptsprache von Sun können Sie direkte Aufrufe auf alle Java-APIs durchführen, die auf einer Plattform verfügbar sind. Das unterscheidet sie beispielsweise von bisher schon vorhandenen Konkurrenzsprachen wie JavaScript59. Aber obwohl JavaFX auf Java basiert, unterscheidet sich die Sprache dennoch in mehreren zentralen Details massiv von der streng objektorientierten Verwandtschaft.
58 Keine Angst, wenn Sie diese Fachbegriffe (noch) nicht verstehen – die Erklärungen sind ja expliziter Bestandteil dieses Kapitels. 59 Obwohl auch mit JavaScript sowohl der Zugriff auf ein Java-API als auch der umgekehrte Weg unterstützt werden. Aber sowohl eingeschränkt als auch nicht direkt.
Kapitel 3
Das betrifft einmal den Bezug zu der Erzeugung von Objekten als auch den Umgang mit der OOP als Gesamtes. Man kann und wird beispielsweise in JavaFX mit Objekten umgehen, aber auch prozedurale Techniken verwenden. JavaFX Script ist also explizit als hybride Sprache konzipiert worden. Und auch die genaue Syntax von JavaFX Script differiert von der von Java in vielen wichtigen Details. In mehreren Situationen fühlt man sich bei JavaFX Script eher an JavaScript denn an Java erinnert, was konsequente Java-Fans teilweise vor echte Glaubensfragen stellen wird. Andere Bestandteile von JavaFX Script sind an Notationen in XML beziehungsweise die XML-Lokalisierungssprache XPath oder auch SQL angelehnt. Und in der Behandlung von Zeichenketten60 scheint sich Sun beispielsweise bei PHP umgesehen zu haben. Ebenso sollten Sie beachten, dass Anweisungen in JavaFX – typisch für ein Skript – einfach sequenziell von oben nach unten abgearbeitet werden. Aber das ist für JavaFX Script nur die halbe Wahrheit. Es bedeutet nämlich nicht, dass beispielsweise oben im Quellcode notierte Aufrufe von Funktionen oder Operationen zwingend auch vorher deklariert sein müssen61. Der Interpreter von JavaFX sortiert gegebenenfalls den Quellcode vor der Interpretation in die richtige Reihenfolge. Er betrachtet ihn also als Ganzes. Wenn Sie sich diese Ausführungen ansehen, haben also sowohl Einsteiger in die Welt von Java als auch erfahrene Java-Programmierer ganz spezifische (wenngleich unterschiedliche) Gründe, warum sie dieses Kapitel durcharbeiten sollten. 62
> >
>
HINWEIS
Der konkrete Blick auf den objektorientierten Ansatz von JavaFX werden wir im nächsten Kapitel in den Fokus stellen. Und JavaFX Script macht für die Erstellung von typischen Applikationen intensiven Gebrauch von GUI-Komponenten aus Swing sowie Java2D und erlaubt damit vor allen Dingen eine leichte Erstellung von grafischen Benutzerschnittstellen. Das haben wir in den ersten Beispielen ja bereits gesehen. Aber auch dieses Thema werden wir erst in späteren Kapiteln62 verfolgen, denn diese Technik basiert einmal explizit auf der OOP. Zum anderen blähen die notwendigen Anweisungen den Quelltext auch ziemlich auf und verstellen damit den Blick auf das, was in diesem Kapitel im Fokus stehen soll. In dem aktuellen Kapitel behandeln wir das grundsätzliche Konzept der Technologie, die Basistypen, Variablen, Funktionen, Arrays, Ausdrücke, Operationen, Literale und andere wesentliche Aspekte der Syntax. Und die Beispiele werden entsprechend optisch nur sehr einfach sein, um nicht den Blick auf die Wesentlichkeiten zu verstellen.
60 Insbesondere der Auswertung von Ausdrücken in Zeichenketten. 61 Was bei einigen Skriptsprachen und auch älteren Programmiersprachen notwendig ist. 62 Die Erstellung von Swing-Applikationen sehen Sie in Kapitel 5 und die Verwendung von Java2D in Kapitel 8.
84
Das Syntaxkonzept von JavaFX Script
3.1 Das grundsätzliche Konzept von JavaFX Wir wollen uns zuerst dem grundsätzlichen Konzept von JavaFX nähern und dabei immer wieder den Bezug zu Java selbst suchen. Sowohl deshalb, weil garantiert viele Java-Programmierer den Umstieg wagen beziehungsweise ihre Kenntnisse in der JavaWelt erweitern wollen, aber vor allem deshalb, weil sie letztendlich auch mit JavaFX echte Java-Applikationen erstellen (wenngleich mit einer übergeordneten Syntaxschicht). Java und JavaFX haben also viele Gemeinsamkeiten, aber es gibt wie schon erwähnt auch Trennendes. Java ist eine streng objektorientierte Programmiersprache, die teils interpretiert und teils kompiliert ist. JavaFX Script hingegen ist eine sequenziell abgearbeitete Skriptsprache, die zudem nicht streng objektorientiert arbeitet. Und auch bezüglich des Umgangs mit der Interpretation muss man sich Gedanken machen.
> >
>
HINWEIS
In dieser Einleitung stecken nun bereits diverse Fachbegriffe, die wir uns erst einmal verdeutlichen müssen. Zwar werden erfahrene Programmierer damit klarkommen, aber diese vertieften Grundlagen in der Programmierung sollen ja im Buch explizit nicht vorausgesetzt werden.
3.1.1 Kompilierung versus Interpretation Stellen wir zuerst das Prinzip der Kompilierung und der Interpretation gegenüber. Was hat es damit auf sich? Beide Prinzipen beschreiben Verfahren zur Übersetzung von lesbarem Klartext in Anweisungen, die ein Computer versteht. Grundsätzlich schreibt man in so genannten höheren Programmiersprachen Quellcode. Das ist dieser lesbare Klartext63. Dieser ist mit zentralen Schlüsselwörtern, die in der Regel der englischen Sprache entnommen sind, und mit anderen Token durchsetzt. Wir haben solchen Quellcode im letzten Kapitel ja bereits mehrfach erstellt.
> >
>
HINWEIS
Ein Token ist ein Zeichen oder eine Zeichenkombination im Quellcode. Ein Token hat eine feste Bedeutung im Rahmen einer Programmiersprache. Das kann ein Schlüsselwort wie for, do oder if sein, aber auch eine Syntaxstruktur wie das Plus- oder Minuszeichen, das Gleichheitszeichen, ein Klammernpaar etc.
63 In der Regel auf Basis von ASCII-Code oder Unicode.
85
Kapitel 3
Dieser für Menschen64 lesbare Quellcode muss zur Ausführung auf dem Rechner in eine Form gebracht werden, die für den Computer verständlich ist. Er muss übersetzt werden – letztendlich irgendwann einmal in etwas, was man als Maschinencode bezeichnet.
> >
>
HINWEIS
Maschinencode oder Maschinensprache ist das, was der Prozessor des Computers versteht und ausführen kann. Es handelt sich um einen Binärcode.
Bei der Art der Übersetzung von Quellcode in Maschinencode gibt es zwei verschiedene Konzepte: Kompilierung Interpretation Ein Parser verarbeitet den Quellcode vor dem konkreten Kompilieren beziehungsweise Interpretieren und zerlegt ihn anhand von Token in kleinere Einheiten. Diese werden dann vom Interpreter oder Compiler übersetzt beziehungsweise verarbeitet. Bei der Kompilierung wird der gesamte Quellcode eines Programms genommen und als Ganzes übersetzt. Das macht man mithilfe eines Compilers. Das Resultat ist eine ausführbare Datei65 oder eine binäre Bibliothek wie eine DLL, die in einer spezifischen Umgebung zum Laufen gebracht oder von einem Programm verwendet werden kann. Bei der Interpretation wird der Quellcode erst zu dem Zeitpunkt übersetzt, zu dem er ausgeführt werden soll. Und dies zeilenweise von oben nach unten. Das bedeutet im allgemeinen Fall, wenn eine Zeile, die oben im Quellcode auftaucht, vom Computer abgearbeitet wird, sind Quellcodezeilen, die weiter unten im Quellcode stehen, noch nicht übersetzt. Wobei Letzteres – wie schon erwähnt – im Fall von JavaFX Script nicht ganz stimmt, denn der Interpreter66 von JavaFX ist »intelligent« und sucht bei Bedarf auch weiter unten im Quellcode notierte Strukturen und bringt den Quellcode im Hintergrund in die richtige Reihenfolge. Nun haben sowohl Interpretation als auch Kompilierung spezifische Vor- und Nachteile. Kompilierter Code ist auf jeden Fall performanter und es kann gewährleistet werden, dass keine syntaktischen Fehler im resultierenden Programm vorliegen. Sollte solch ein syntaktischer Fehler im Quellcode vorliegen, wird das der Compiler entdecken und das Programm nicht zu Ende übersetzen. 64 Zumindest solchen Menschen, die ein bisschen was von Programmierung verstehen. Für andere Personen ist Quellcode oft unlesbares Zeug, das höchstens Panik auslöst. Wobei solche Programmierlaien oft auch Programmierer nicht für Menschen halten ;-). 65 Zum Beispiel eine .exe-Datei unter Windows. 66 Oder eigentlich der Parser, aber diese Feinheiten sollen keine Rolle spielen.
86
Das Syntaxkonzept von JavaFX Script
> >
>
HINWEIS
Fast alle Applikationen, die Sie auf Ihrem PC vorfinden, sind bereits kompiliert.
Interpretierter Code ist, da noch nicht in konkreten Maschinencode für einen spezifischen Prozessor übersetzt, universeller und leichter zu verteilen. Zudem ist die Datei, die ein Anwender erhalten muss, um ein Vielfaches kleiner als die bereits voll übersetzte, ausführbare Datei67. Und Interpretercode ist oft einfacher strukturiert und damit leichter zu lernen. Der Anwender, bei dem ein zu interpretierendes Programm oder Skript ausgeführt werden soll, benötigt allerdings immer einen passenden spezifischen Interpreter für eine Programmier- oder Skriptsprache.
> >
>
HINWEIS
Interpretation findet man sehr oft im Internet bei Skriptsprachen. So ist beispielsweise JavaScript eine interpretierte Sprache.
3.1.2 Bytecode – das Beste aus Interpretation und Kompilierung Mittlerweile findet man sehr oft auch Mischverfahren aus Kompilierung und Interpretation. Beispielsweise auch bei Sprachen des .NET-Konzepts von Microsoft und Java, wie bereits oben erwähnt. Bei Java wird der Quellcode zuerst in so genannten Bytecode kompiliert, der dann in Form von .class-Dateien gespeichert wird und das Beste aus zwei Welten vereint. Bei diesem Bytecode handelt es sich um ein architekturneutrales Object-Code-Format. Ferner ist er binär, aber so lange nicht vollständig und lauffähig, bis er von der Java-Laufzeitumgebung interpretiert wird. Da jede Java-Laufzeitumgebung plattformspezifisch ist, arbeitet das endgültige ausgeführte Programm auf dieser spezifischen Plattform. Diese Mischform ist das Geheimnis der Plattformneutralität von Java und letztendlich auch JavaFX.
3.1.3 Die zusätzliche Architekturschicht in JavaFX Allerdings ist bei JavaFX sozusagen noch eine weitere Ebene im Architekturmodell eingezogen. Der Quellcode in einer JavaFX Script-Applikation beschreibt keinen nativen Java-Quellcode, sondern ist ein Skriptcode mit der Dateierweiterung .fx, der bei der Interpretation vorhandenen Bytecode nutzen kann68 und der zudem vor der tatsächlichen Interpretation im Hintergrund syntaktisch aufbereitet wird. Und er wird selbst – trotz der Abweichung in der Syntax des JavaFX-Quellcodes – letztendlich ebenfalls im Hintergrund wie eine gewöhnliche Java-Applikation vom JavaFX-Laufzeitsystem in Java-Bytecode übersetzt und in Form von temporären .class-Dateien 67 Das spielt vor allen Dingen im Internet eine große Rolle. 68 Das gesamte JavaFX-API besteht im Kern aus Java-Klassen mit der Erweiterung .class.
87
Kapitel 3
bereitgestellt. Ebenso können und werden über das JavaFX-Standard-API hinaus .classDateien auch direkt von JavaFX-Applikationen verwendet und mit ausgeliefert. Diese werden allerdings – wie auch das JavaFX-Standard-API – werden meist in Form einer komprimierten .jar-Datei zur Verfügung gestellt.
Abbildung 3.1: Eine JavaFX-Applikation liefert meist auch direkt eine Bibliothek mit gepackten .class-Dateien aus
Aber wie gesagt – bei JavaFX werden dennoch die Quellcode-Anweisungen zur Laufzeit übersetzt und das bedeutet, die Interpretation wird hier an zwei Stellen verwendet: 1. Die normale Interpretation von Java-Bytecode, wie sie auch bei allen anderen Typen an Java-Applikationen verwendet wird. 2. Die vorangehende Interpretation der Skriptbefehle von JavaFX Script, um die eigentliche Applikation zusammenzufügen. Die Interpretation des Bytecodes bei Java-Applikationen ist mittlerweile sehr ausgereift und durch diverse Maßnahmen performant. Aber die vorangehende zusätzliche Interpretation der Skriptbefehle im Rahmen von JavaFX Script drängt unweigerlich die
88
Das Syntaxkonzept von JavaFX Script
Frage auf, wie es mit der Performance bei JavaFX Script aussieht, die ja allgemein bei einer Skripttechnologie ein Problem darstellt? Nach Aussage von Sun ist jedoch die Architektur von JavaFX Script hochperformant konzipiert worden, denn alle GUI-Komponenten sowie die Objekte der Back-endApplikation sind in purem Java implementiert und JavaFX-Skriptcode wird nur zur Erstellung, Konfiguration und Verbindung von solchen Komponenten verwendet. Diese Schritte stellen in der Gewichtung der letztendlich vom Prozessor ausgeführten Schritte einer JavaFX-Applikation also einen verschwindend geringen Anteil dar, der die Performance der gesamten Applikation nur absolut unwesentlich beeinflusst.
3.2 Ein paar elementare Grundregeln zur Syntax von JavaFX Die Eingabe von Quellcode ist in der Programmierung in der Regel absolut nicht fehlertolerant. Das bedeutet, ein kleiner Fehler wie ein vergessenes Komma oder eine fehlende Klammer kann bereits die Übersetzung beziehungsweise Ausführung der gesamten Applikation verhindern. Das unterscheidet Skript- und Programmiersprachen beispielsweise von einer Dokumentenbeschreibungssprache wie HTML, die von einem Browser nach dem Prinzip der Fehlertoleranz interpretiert wird und durchaus massive strukturelle Fehler in einem Dokument enthalten kann. Zwar gibt es einige Programmier- und Skriptsprachen, die dennoch für einige Situationen eine gewisse Fehlertoleranz aufweisen (beispielsweise kann in einigen Programmiersprachen für eine Anweisung ein im Grunde verbindliches Semikolon zum Beenden einer Anweisung weggelassen werden, wenn es sich um die letzte Anweisung in einem Block handelt), aber diese Fälle sind streng limitiert und lassen in der Regel auch nur definierte Abweichung von einer Standardvorgabe zu69. Java ist nun auch syntaktisch eine sehr strenge Sprache. Das stört zwar Einsteiger oft. Erfahrenen Programmierern gefällt es jedoch sehr gut, dass es keine Ausnahmen und unklaren Situationen gibt und Java dadurch extrem logisch ist. In JavaFX Script gelten nun im Wesentlichen die gleichen Grundregeln zur Syntax wie in Java, obwohl die Strenge von Java in JavaFX Script an einigen Stellen etwas aufgeweicht und auch die Syntax teilweise etwas abgewandelt70 wurde. Diese Grundregeln von Java respektive JavaFX sollten Sie gleich von Anfang an beachten, um nicht unnötige Fehler zu machen, die Sie dann sowieso vor einer Übersetzung beseitigen müssen:
69 So gesehen handelt es sich also auch dann nicht um echte Fehler. 70 Hier müssen besonders erfahrene Java-Programmierer aufpassen.
89
Kapitel 3
Groß- und Kleinschreibung im Quelltext ist grundsätzlich relevant. Schlüsselwörter der Sprache dürfen nicht als Bezeichner verwendet und nicht getrennt werden. Zumindest nicht ohne eine Kennzeichnung. JavaFX stellt ein Konstrukt mit so genannten französischen Anführungszeichen bereit, bei denen Schlüsselwörter dann doch als Bezeichner fungieren können. Aber sie sind dann speziell markiert. Darauf gehen wir natürlich detailliert ein (siehe Seite 149). Zeichenketten (in Hochkommata eingeschlossene Zeichen) dürfen im Allgemeinen in einer Programmier- oder Skriptsprache ohne spezielle Vorkehrungen nicht auf mehrere Zeilen verteilt werden. Sie können allerdings in nahezu jeder Programmier- und Skriptsprache eine Zeichenkette aus mehreren Teilen zusammensetzen. Nun geht JavaFX bei Zeichenketten einen etwas anderen Weg als fast alle anderen Programmier- und Skriptsprachen und insbesondere auch Java. JavaFX verwendet zwei Formen an Zeichenketten (mit einfachen und doppelten Hochkommata), was unterschiedliche Möglichkeiten eröffnet. Und im Gegensatz zu Java und allen mir sonst noch bekannten Programmier- und Skriptsprachen können (und werden) in JavaFX Zeichenketten Zeilenumbrüche enthalten, wenn sie in doppelte Hochkommata eingeschlossen sind71 (siehe Seite 115)! Zu jeder geöffneten Klammer muss es genau eine zugehörige geschlossene Klammer gleichen Typs geben. Fehlende oder überflüssige Klammern sind einer der häufigsten Fehler in der Quelltexteingabe. Blöcke (Zusammenfassungen von Anweisungen) werden mit geschweiften Klammern gebildet. Kommentare werden entweder mit // (einzeiliger Kommentar bis zum Zeilenende) eingeleitet und mit /* begonnen und mit */ beendet (mehrzeiliger Kommentar). Leerzeichen und andere Whitespace-Zeichen (unsichtbare Zeichen) wie der Tabulator oder ein Zeilenumbruch können immer da in beliebiger Anzahl stehen, wo verschiedene Token getrennt werden. Auf Leerzeichen und andere Whitespace-Zeichen kann zwischen zu trennenden Token verzichtet werden, wenn dort ein anderes Trennzeichen wie ein Komma oder eine Klammer steht. In Java muss jede Anweisung mit einem Semikolon beendet werden. Das ist in JavaFX auch der Fall, obwohl es manchmal nicht so scheint. Das Problem resultiert daraus, dass Anweisungen in JavaFX eine etwas andere Struktur als in Java haben können und es damit für Umsteiger von anderen Sprachen etwas verschleiert wird, wo genau eine Anweisung zu Ende ist. 71 Eine Zeichenkette wird also im Editor auf mehrere Zeilen verteilt.
90
Das Syntaxkonzept von JavaFX Script
3.3 Die Basistypen von JavaFX Script und Variablen Ein Typ beziehungsweise Datentyp gibt in einer Computersprache an, wie ein einfaches Objekt (wie zum Beispiel eine Variable oder Literal) im Speicher des Computers dargestellt wird.
> >
>
HINWEIS
Ich stelle Programmiereinsteiger in meinen Programmierkursen fast immer die Frage, was eine Variable ist. In der Regel erhalte ich als Antwort eine Definition der Art, dass eine Variable irgendetwas Veränderbares ist. Aus der Schulmathematik erinnern sich fast alle Teilnehmer an den Begriff einer Variablen. In der Programmierung muss man jedoch etwas anders an die Definition herangehen. Eine Variable sollte man als eine Stelle im Hauptspeicher des Rechners verstehen, deren Inhalt man auslesen und durch Zugriff aus einer Programmiersprache verändern kann. Ein Literal ist hingegen ein Wert wie eine Zahl, ein einzelnes Zeichen oder eine Zeichenkette. Literale werden in Ausdrücken verwendet und oft Variablen zugewiesen. Beides – Variablen beziehungsweise deren Bezeichner und Literale – sind Token, die in jeder Programmier- und Skriptsprache vorkommen.
3.3.1 Der Datentyp Ein Datentyp legt in einer Programmiersprache fest, wie viel Platz für ein einfaches Objekt im Speicher des Computers reserviert wird und welche Arten von Werten in diesem Speicherbereich abgelegt werden können. Dies impliziert für numerische Werte auch einen Wertebereich. Der Datentyp enthält ebenfalls Informationen darüber, welche Operationen mit und an ihm (beziehungsweise dem einfachen Objekt) ausgeführt werden können. Viele Computersprachen lassen es beispielsweise nicht zu, dass mit einer alphanumerischen Zeichenfolge (also Texten) direkte arithmetische Operationen durchgeführt werden72. Java selbst besitzt nun acht primitive Datentypen73, die explizit plattformunabhängig sind, und drei so genannte Referenzdatentypen.
72 Das ist meist auch sinnvoll. Oder was soll "Apfel" geteilt durch "Birne" ergeben ;-)? 73 Im Detail sind das in Java die ganzzahligen numerischen Typen byte, short, int und long mit Vorzeichen, die beiden Gleitkommatypen float und double, char für Zeichen über eine ganzzahlige 16 Bit-Unicodedarstellung (ohne Vorzeichen) und der 1 Bit große Wahrheitswert boolean.
91
Kapitel 3
> >
>
HINWEIS
Ein primitiver Datentyp (auch einfacher Datentyp genannt) ist direkt in die Programmiersprache eingebaut. Etwa die Darstellung für eine Zahl, einen Wahrheitswert oder einen Buchstaben. Streng genommen darf es in objektorientierten Programmiersprachen gar keine primitiven Datentypen geben, aber Sun hat ob der besseren Verwendbarkeit und einem sinnvollen Bezug zur traditionellen Programmierung bei der Einführung von Java mit diesem Dogma gebrochen. Ein Referenzdatentyp ist hingegen ein Verweis (oft auch Zeiger oder Pointer genannt) auf einen bestimmten Speicherbereich. Damit werden in der Regel Objekte referenziert. In Java sind alle Referenztypen 32 Bit groß. Ihnen sollte auffallen, dass also die oft zu hörende Aussage »Java hat keine Pointer« so nicht richtig ist. Aber Java verwendet die Pointer über diese Referenztypen indirekt und versperrt einem Programmierer den direkten Zugriff auf Speicherbereiche. Das ist ein immenser Stabilitäts- und Sicherheitsvorsprung von Sprachen, bei denen ein Programmierer über Pointer direkt auf Speicherbereichen agiert.
Im Gegensatz zu Java unterstützt JavaFX nur vier primitive Basistypen, deren Gegenstück zudem in Java teils über Referenztypen und nicht primitive Datentypen abgebildet werden. Und wenn man genauer hinschaut, verwaltet JavaFX diese vier primitiven Basistypen als Referenztypen74, was JavaFX damit massiv von Java unterscheidet: Der Datentyp String dient zur Beschreibung von Zeichenketten. Das sind in JavaFX alle Texte, die in doppelte oder einfache Hochkommata eingeschlossen werden. An dieser Stelle sehen Leser mit Java-Erfahrung einen deutlichen Unterschied zu Java, wo Zeichenketten ausschließlich in doppelte Hochkommata eingeschlossen werden dürfen und einfache Hochkommata ausschließlich für Character (einzelne Zeichen – in Java ist das der primitive Datentyp char) verwendet werden! Aber beispielsweise in JavaScript oder PHP kennt man ebenso diese zweifache Verwendung der Kennzeichnung von Zeichenketten. Da JavaFX jedoch auch einzelne Zeichen75 grundsätzlich als Zeichenketten betrachtet, ist hier eine Unterscheidung zwischen einfachen und doppelten Hochkommata nicht notwendig. Und wie auch in PHP werden in JavaFX Zeichenketten in doppelten und einfachen Hochkommata vom System etwas anders behandelt. Die doppelte Form der Kennzeichnung von Zeichenketten in JavaFX eröffnet einige interessante Möglichkeiten76.
74 Das bedeutet als Konsequenz, dass sie Methoden bereitstellen. 75 Diese werden in Java wie gesagt über den primitiven Datentyp char abgebildet und streng von Zeichenketten (das sind in Java im Gegensatz dazu keine primitiven Datentypen, sondern Objekte) unterschieden. 76 Darauf kommen wir noch genauer zu sprechen (siehe Seite 113).
92
Das Syntaxkonzept von JavaFX Script
Der Datentyp Boolean ist ein Typ für einen Wahrheitswert. Das sind die Token true für wahr und false für falsch. Solche Wahrheitswerte werden im Wesentlichen bei Vergleichen verwendet. Im Grunde ist hier kein wesentlicher Unterschied zu Java zu sehen, nur kennt Java neben der Wrapper-Klasse77 Boolean auch den primitiven Datentyp boolean, der in der Praxis auch weit häufiger verwendet wird. Der Datentyp Number dient zur Beschreibung von allgemeinen numerischen Werten über eine Objektdarstellung. In Java gibt es diese Wrapper-Klasse für Zahlen auch, aber in der Praxis verwendet man meist die primitiven Datentypen sowie gelegentlich abgeleitete Klassen von Number. Der Datentyp Integer dient zur Beschreibung von primitiven ganzzahligen numerischen Werten mit Vorzeichen und großen Ganzzahlen. Auch hier gibt es ein direktes Gegenstück in Java. Daneben gibt es jedoch in Java zusätzlich die WrapperKlassen Byte, Short und Long, um Gegenstück für alle ganzzahligen primitiven Datentypen bereitzustellen. Und auch bei ganzen Zahlen verwendet man in der Praxis in Java fast immer die primitiven Datentypen. Diese Basistypen von JavaFX korrespondieren mit den Datentypen von Java also wie folgt: JavaFX
java.lang.Integer, java.lang.Byte, java.lang.Short, java.lang.Long, java.math.BigInteger, byte, short, int, long
Tabelle 3.1: Die Datentypen von JavaFX versus den Datentypen von Java
Beispiele: var s = "Hallo"; var n = 1.5; var b = true; Listing 3.1: Datentypen bei Variablendeklarationen 77 Eine Wrapper-Klasse (kurz Wrapper) in Java ummantelt einen primitiven Datentyp und erlaubt so den Austausch von Werten zwischen primitiven Datentypen und Klassen beziehungsweise Objekten.
93
Kapitel 3
> >
>
HINWEIS
Nun wird erfahrenen Java-Programmierern auffallen, dass die Kompatibilität der Datentypen zwischen Java und JavaFX einige automatische Anpassungen notwendig macht, wenn Argumente an eine Java-Methode übergeben werden oder ein entsprechender Rückgabewert geliefert wird. Immerhin muss beispielsweise ein Referenztyp Integer in JavaFX in Java über einen primitiven Datentyp int verarbeitet werden oder umgekehrt. Das JavaFX-System löst die Umwandlung automatisch aus.
> >
>
HINWEIS
Eine Methode können Sie sich erst einmal einfach nur als ein Unterprogramm vorstellen.
3.3.2 Die Variablendeklaration in JavaFX Die skizzierten Beispiele oben haben bereits angedeutet, dass in JavaFX ein Schlüsselwort var im Einsatz ist, das in dieser Form im reinen Java nicht vorkommt78. Allerdings sollten JavaScript-Programmierer dieses Schlüsselwort und den Einsatz kennen – das Verfahren in JavaFX Script ist verwandt. Aber glücklicherweise ist der Einsatz des Schlüsselwortes var in JavaFX strenger reglementiert als in JavaScript. So muss es für einen bestimmten Anweisungstyp zwingend notiert werden und ist nicht optional wie in JavaScript. Mit diesem Schlüsselwort var führen Sie eine neue Variable ein. Eine solche Anweisung nennt man eine Deklaration der Variablen. Beispiel: var z; Listing 3.2: Eine Variablendeklaration ohne Festlegung des Datentyps
Bei der Deklaration können Sie auch gleich den Datentyp der Variablen spezifizieren. Beispiel: var z: String; Listing 3.3: Eine Variablendeklaration mit Festlegung des Datentyps
Wie Sie sehen, folgt dem Schlüsselwort var der Bezeichner79 der Variablen, dann ein Doppelpunkt und anschließend der Datentyp.
78 Obwohl es in Java reserviert ist. 79 Also der Name, unter dem sie in den folgenden Anweisungen des Quelltexts angesprochen werden soll.
94
Das Syntaxkonzept von JavaFX Script
Deklaration mit Initialisierung Nun können Sie auch bei der Deklaration einer Variablen bereits einen Wert geben. Das nennt man die Initialisierung. Beispiel: var z: String = "RJS" Listing 3.4: Eine Variablendeklaration mit Festlegung des Datentyps in Initialisierung
Mit dem Gleichheitszeichen wird der Variablen ein Anfangswert zugewiesen. Der Anfangswert kann ein Literal sein, aber auch berechnet oder als Ergebnis einer Funktion geliefert werden. Und da auch keine Wertzuweisung am Anfang erfolgen muss, könnte man das auch auf zwei Zeilen verteilen: var nums; // Deklaration nums = 1; // Initialisierung Listing 3.5: Ein Beispiel für Verteilung der Deklaration und der Wertzuweisung
!
!
!
ACHTUNG
Diese Form der Variablendeklaration unterscheidet sich massiv von der Syntax in Java.
Deklaration ohne explizite Typfestlegung Die explizite Festlegung des Datentyps bei der Deklaration ist nun optional in JavaFX. Es gibt einige Abwandlungen von dieser Form. Wenn Sie den Datentyp bei der Deklaration nicht auf diese Weise (also einem Doppelpunkt nachgestellt) festlegen, wird der JavaFX-Interpreter den Datentyp der Variablen aus dem Datentyp des zugewiesenen Literals oder Ausdrucks implizit festlegen. Da man die Wertzuweisung einer Variablen auch nach einer Deklaration vornehmen kann, bedeutet das, dass die Variable bis zum Zeitpunkt der impliziten Typzuweisung durch den Typ eines Literals oder Ausdrucks keinen sinnvollen Wert repräsentiert. Allerdings sollten Sie sich noch einmal vergegenwärtigen, dass JavaFX ausschließlich mit Referenztypen arbeitet, und die sind im Typ und der Größe eindeutig. Die Referenzvariable weist also in so einem Fall einfach noch nicht gezielt auf einen bestimmten Speicherbereich. Sie ist aber in der Grundstruktur festgelegt.
95
Kapitel 3 8081
> >
>
HINWEIS
Man kann durchaus geteilter Meinung sein, ob die optionale Verwendung einer expliziten Festlegung eines Datentyps in einer Programmierer- oder Skriptsprache nun von Vorteil oder von Nachteil ist. Auf der einen Seite erleichtert eine (optionale) implizite Festlegung des Datentyps für Einsteiger den Umgang mit Variablen erheblich. Auch wird der Quellcode kleiner. Und zudem kann man dynamisch auf gewisse Situationen reagieren, bei denen sich ein Datentyp einer Variablen erst zur Laufzeit ergibt. Auf der anderen Seite wird die Klarheit und Wartbarkeit eines Programms beziehungsweise Skripts reduziert. Gerade Programmierer aus strengen Sprachen wie Java schätzen den unabdingbaren Zwang, bei der Deklaration den Datentyp angeben zu müssen80. Je weniger Ausnahmen und verschieden zu behandelnde Situation es in einer Sprache gibt, desto logischer ist die Sprache. In JavaFX kontrolliert das System allerdings bei einer Angabe des Datentyps für eine Variable, ob der Datentyp des zugewiesenen Werts mit diesem übereinstimmt. Ebenso kann in JavaFX ein einmal zugewiesener Datentyp für eine Variable nicht mehr im Laufe des Skripts geändert werden! Dies ist in so genannten lose typisierten Sprachen wie JavaScript oder PHP beispielsweise möglich. Dort kann man auch eine Variable ohne konkrete Deklaration über eine Wertzuweisung zu einem bisher noch nicht verwendeten Bezeichner einführen81. Das ist ebenso in JavaFX nicht möglich, was auch für erfahrene Java-Programmierer die Bauchschmerzen in Grenzen halten sollte.
!
!
!
ACHTUNG
Eine Deklaration von mehreren Variablen in einer Anweisung (was in Java möglich ist) geht in JavaFX nicht. Weder mit noch ohne direkte Initialisierung. Also etwas der folgenden Art wäre in JavaFX falsch: var a, v; var a = 5, b = 6; Listing 3.6: Das geht in JavaFX nicht
3.3.3 Festlegung der Kardinalität einer Variable In JavaFX ist es nun möglich, bei der Deklaration einer Variablen die so genannte Kardinalität (Häufigkeit des Vorkommens) der Variable festzulegen.
80 Dazu zähle ich mich persönlich auch, obwohl ich sehr viel mit Sprachen wie JavaScript und PHP arbeite, in denen so eine implizite Festlegung des Datentyps sogar nur ausschließlich möglich ist. 81 Dieses Verhalten erleichtert Einsteigern den Umgang mit Variablen noch einmal ziemlich. Auf der anderen Seite wird die Wartbarkeit jedoch genauso extrem erschwert (es können unbeabsichtigt Variablen entstehen, wo man einer bestehenden Variable eigentlich nur einen neuen Wert zuweisen wollte). Und im Fehlerfall kann die Suche nach einem Fehler äußerst diffizil werden.
96
Das Syntaxkonzept von JavaFX Script
> >
>
HINWEIS
So etwas in der Art ist beispielsweise in der DTD (Document Type Definition) vollkommen analog möglich. Damit kann zum Beispiel für ein XML-Dokument die Kardinalität eines Elements festgelegt werden. In Programmier- und Skriptsprachen ist so etwas jedoch eher ungewöhnlich. Die Kardinalität wird in JavaFX vor allem bei der Beschreibung von Attributen einer Klasse eine wichtige Rolle spielen.
Um die Kardinalität bei der Deklaration festzulegen, verwenden Sie einen der Operatoren ?, +, oder *, wie sie genauso beispielsweise in einer DTD (allerdings mit kleinen Abweichungen in der Bedeutung) verwendet werden.
> >
>
HINWEIS
Ein Operator ist ein Token, über den eine bestimmte Operation angezeigt wird, die ein Interpreter oder Compiler ausführen soll. Etwa eine Wertzuweisung, eine mathematische Operation, ein Vergleich etc.
Operator
Bedeutung
?
Optional – kann also auch fehlen.
+
Mindestens einmal oder mehr
*
Null oder mehrmals
Tabelle 3.2: Die Operatoren zur Angabe der Kardinalität einer Variablen
Beispiel: var zahlen:Number* = 1; Listing 3.7: Ein Beispiel für die Angabe einer Kardinalität
In dem Listing wird einen Variable zahlen eingeführt und initialisiert, deren Werte vom Typ Number und null oder mehrfach vorkommen. Da in JavaFX neben der Kardinalität auch die Typangabe optional ist, könnte man für eine Variablendeklaration mit Initialisierung auch Folgendes schreiben: var zahlen* = 1; Listing 3.8: Ein Beispiel für die indirekte Angabe einer Kardinalität
97
Kapitel 3
3.4 Funktionen und Prozeduren Erfahrene und vor allem überzeugte Java-Programmierer (oder allgemein Programmierer aus dem Umfeld der streng objektorientierten Programmierung) werden bei den Schlagwörtern Funktionen und Prozeduren im Rahmen des Java-Universums wahrscheinlich erst einmal eine schwere Sinnkrise bekommen. Es zählt ja zu den elementarsten Paradigmen der objektorientierten Programmierung, dass es dort keinerlei objektungebundenen Unterprogramme gibt und geben darf. Manche OO-Prediger gehen sogar noch weiter und sagen, dass der große Vorteil der OOP neben dem Weglassen von globalen Variablen der Verzicht auf Funktionen und Prozeduren ist! Denn damit wird die Wiederverwendbarkeit von Programmbestandteilen gewährleistet.
> >
>
HINWEIS
Eine Funktion stellt in der klassischen (oder auch prozedural genannten) Programmierung ein Unterprogramm dar. Funktionen bildeten den Kern der so genannten modularen Programmierung, die in der »Frühzeit« der EDV eine erste Strukturierung von größeren Programmen in einzelne Module mit einer begrenzten Wiederverwertbarkeit gestattete. Im Gegensatz zu einer Methode in der OOP ist eine Funktion jedoch nicht an ein Objekt gebunden, sondern kommt als eigenständige Struktur daher, die direkt über ihren Bezeichner aufgerufen werden kann – ohne einem Objekt dazu eine Botschaft zu schicken (d. h. ohne ein vorangestelltes Objekt). Eine Funktion liefert nach Beendigung ihrer Tätigkeit einen so genannten Rückgabewert (ein Ergebnis) an den Aufrufer der Funktion. In JavaFX muss jede Funktion einen Rückgabewert liefern.
> >
>
HINWEIS
Eine Prozedur ist im Allgemeinen eine Funktion ohne Rückgabewert. In JavaFX ist das Verständnis einer Prozedur aber etwas anders. Hier kann eine Prozedur durchaus einen Rückgabewert liefern, muss es aber nicht. Diese Verwendung des Begriffs einer Prozedur unterscheidet sich von den meisten anderen prozeduralen Sprachen. Da man in JavaFX bei einer Prozedur auch von einer Operation spricht, ist die konsequente Verwendung dieses Begriffs meines Erachtens sinnvoller.
Aber um es noch einmal zu betonen – JavaFX Script ist nicht streng objektorientiert, sondern eben eine Skriptsprache, die auf einer strengen OO-Welt operiert und ein eigenes Sprachkonzept darauf aufsetzt. Und dieses arbeitet nun mal mit Funktionen und Prozeduren82.
82 Die Experten bei Sun werden sich schon was dabei gedacht haben. Und auch strukturell mit JavaFX Script verwandte Skriptsprachen wie JavaScript oder PHP arbeiten ebenfalls mit Funktionen als auch Objekten.
98
Das Syntaxkonzept von JavaFX Script
3.4.1 Funktionen in JavaFX JavaFX-Funktionen repräsentieren eine reine funktionale Teilmenge der Programmiersprache selbst. Der Körper einer Funktion darf nur eine Reihe an Variablendeklaration und eine return-Anweisung enthalten. Dies gestattet natürlich nur eine sehr eingeschränkte Verwendung von Funktionen.
> >
>
HINWEIS
Eine return-Anweisung in einer Funktion oder Methode liefert ein Ergebnis (den Rückgabewert) an den Aufrufer der Funktion respektive Methode, der dann verarbeitet werden kann. Entweder erfolgt die Verarbeitung direkt oder der Rückgabewert wird einer Variablen zugewiesen. Es handelt sich hierbei um eine so genannte Sprunganweisung. Diese gibt in einem Programm oder Skript den Programmfluss bei ihrem Aufruf unmittelbar entweder an den Anfang oder das Ende des derzeitigen Blocks weiter (siehe auch Seite 125).
Die Deklaration einer Funktion erfolgt mit dem Schlüsselwort function, dem der Bezeichner der Funktion und ein Klammernpaar folgen. In den Klammern kann man optional Übergabewerte an die Funktion angeben, die dann innerhalb der Funktion als lokale Variablen gelten und nur dort zugänglich sind.
> >
>
HINWEIS
Eine lokale Variable ist nur innerhalb der Struktur verfügbar, in der sie definiert wurde. In der Regel ist eine solche Struktur eine Funktion beziehungsweise allgemein Unterprogramm, aber es gibt auch Sprachen (etwa Java oder JavaFX), in denen eine lokale Variable auf einen Block oder einen begrenzten Bereich beschränkt werden kann.
Beachten Sie, dass kein Datentyp für den Rückgabewert als auch die Parameter angegeben wird, da JavaFX eine statisch typisierte Sprache ist. Aber schauen wir uns eine Funktionsdeklaration samt dem Aufruf in einer kleinen, aber vollständigen JavaFX-Applikation einmal an. In dem Beispiel soll mit dem Aufruf zweier Funktionen ein Ergebnis berechnet werden, das dann in der Folge in einem Label innerhalb eines kleinen Fensters angezeigt werden soll (den Quelltext finden Sie auf der Buch-CD im Ordner javafxapp4): 01 02 03 04 05 06 07 08 09
import javafx.ui.Frame; import javafx.ui.Label; function zahl(a, b) { var x = a + b; var y = a - b; var ergeb = (sq(x) / sq (y)).toString(); return ergeb; }
In den Zeilen 4 bis 9 wird eine Funktion zahl() mit Übergabewerten an die Funktion definiert. Die Parameter mit den Bezeichnern a und b stellen in der Funktion wie gesagt lokale Variablen innerhalb der Funktion dar, die in unserem Beispiel für interne Berechnungen verwendet werden. Auch wenn Sie arithmetische Operatoren im Detail noch kennen gelernt haben, werden Ihnen die Addition und Subtraktion in Zeile 5 und 6 mit Sicherheit vertraut sein. Die Ergebnisse der jeweiligen Operationen werden in den Variablen x und y, die in der Funktion lokal eingeführt werden, gespeichert. In Zeile 7 wird eine weitere Variable mit dem Bezeichner ergeb eingeführt, der das Ergebnis einer Berechnung zugewiesen wird. Die Berechnung verwendet den Rückgabewert einer weiteren Funktion mit Namen sq(), die in den Zeilen 10 bis 12 definiert ist und das Quadrat des Übergabewertes als Rückgabewert liefert. Beachten Sie, dass der Datentyp der Variablen ergeb ein String ist. Diesen Datentyp benötigen wir, wenn wir das Ergebnis der Berechnung der Eigenschaft text eines Labels zuweisen wollen (das sehen Sie in Zeile 15). Da numerische Typen im JavaFX als Objekte zu sehen sind, besitzen sie auch Methoden. Insbesondere besitzt jedes Objekt wie in Java selbst eine Methode toString(), die die Stringrepräsentation des gespeicherten Werts des Objektes liefert. Diese Methode wenden wir in dem Beispiel an und die resultierende Stringrepräsentation wird als Rückgabewert in Zeile 8 an den Aufrufer weitergegeben. Von Zeile 13 bis Zeile 19 sehen Sie die Syntax, um in JavaFX ein Fenster mit einem Label aufzubauen, mit gewissen Eigenschaften zu versehen und anzuzeigen. Genau genommen wird hier über eine so genannte deklarative Syntax ein Objekt der Klasse javafx.ui.Frame erzeugt. Darauf gehen wir im nächsten Kapitel genauer ein.
Abbildung 3.2: Die Zahl wurde unter Verwendung von zwei Funktionen ermittelt
100
Das Syntaxkonzept von JavaFX Script
> >
>
HINWEIS
Die Reihenfolge, in der Funktionen im Quelltext deklariert werden, ist im Allgemeinen nicht von Bedeutung. Wie schon angedeutet, formt der Interpreter bei Bedarf den Quellcode vor der Interpretation intelligent um. Das heißt, die nachfolgende Umstrukturierung des Beispiels eben ist vollkommen äquivalent. Die aufgerufenen Funktionen werden erst hinter der Stelle deklariert, an der sie aufgerufen werden. 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19
import javafx.ui.Frame; import javafx.ui.Label; Frame { content: Label { text: zahl(4,5) width: 100 } visible: true } function sq(n) { return n * n; } function zahl(a,b) { var x = a + b; var y = a - b; var ergeb = (sq(x) / sq (y)).toString(); return ergeb; }
Listing 3.10: Obwohl die Funktionen erst hinter der Stelle deklariert werden, an der sie aufgerufen werden, funktioniert die Sache
3.4.2 Prozeduren beziehungsweise Operationen Neben Funktionen stellt JavaFX wie gesagt auch explizit Prozeduren zur Verfügung. Es ist bemerkenswert, dass eine moderne Skriptsprache damit scheinbar wieder Gräben aufreißt, die man vor vielen Jahren bereits mühsam zugeschüttet hatte. Die explizite Trennung zwischen einer Prozedur und einer Funktion wurde damals in den meisten Skript- als auch Programmiersprachen aufgehoben, da die Unterscheidung, ob ein Rückgabewert vorhanden ist oder nicht, für die meisten Programmierer mehr Ärger als Vorteile bedeutet hat. Und gerade in der objektorientierten Programmierung unterscheidet man bei Methoden ganz bewusst nicht mehr zwischen diesen beiden Arten eines Unterprogramms. Aber in JavaFX wird wieder bewusst eine solche Unterscheidung vollzogen. Prozeduren, die wie schon erwähnt in JavaFX auch Operationen83 genannt werden und mit dem optionalen Rückgabewert auch von klassischen Prozeduren abweichen, sind viel 83 Darauf kommen wir gleich genauer zu sprechen.
101
Kapitel 3
flexibler als Funktionen. Sie können im Gegensatz zu Funktionen in JavaFX eine beliebige Art an Anweisungen enthalten – inklusive Bedingungen, Schleifen, Befehle zur Ausnahmebehandlung etc. In JavaFX werden Prozeduren oder Operationen mit einem eigenen Schlüsselwort bei der Deklaration eingeleitet84 – operation. Sehen wir uns ein Beispiel an (das Beispiel ist auf der Buch-CD im Ordner javafxoperation1 zu finden): 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17
import java.lang.StringIndexOutOfBoundsException; import java.lang.System; import java.lang.StringIndexOutOfBoundsException; operation substring(s:String, n:Number): String { try { return s.substring(n); } catch (e:StringIndexOutOfBoundsException) { return "Der Text hat weniger Zeichen als der Index"; } } System.out.println(substring("Hau System.out.println(substring("Hau System.out.println(substring("Hau System.out.println(substring("Hau
Dich Dich Dich Dich
raus", raus", raus", raus",
1)); 5)); 10)); 15));
Listing 3.11: Die Definition und Anwendung einer Prozedur in JavaFX
Das Beispiel definiert eine Prozedur mit Namen substring(). Die Prozedur hat zwei Argumente. Das erste Argument ist ein String, das zweite Argument eine Zahl vom Typ Number. Die Prozedur liefert einen Teil String des ersten Parameters ab der spezifizierten Stelle, in dem zweiten Argument angegeben wird.
> >
>
HINWEIS
In dem Beispiel kommt so eine genannte Ausnahmebehandlung zum Einsatz. Die Grundlagen dazu haben wir bisher noch nicht erarbeitet. Sie folgen aber im Laufe des Buchs. Für jetzt können Sie den Aufbau der Prozedur so verstehen, dass nur dann ein Teilstring geliefert wird, wenn der als zweites Argument übergebene Index nicht größer als die Länge des Strings ist, der als erstes Argument der Prozedur übergeben wird.
Beachten Sie, dass die Prozedur in Abhängigkeit von der Situation zwei verschiedene Rückgabewerte liefert (in Zeile 7 den Teil-String und in Zeile 10 eine Fehlermeldung).
84 Nicht mit function.
102
Das Syntaxkonzept von JavaFX Script
Das ist die Ausgabe des Beispiels: au Dich raus ich raus aus Der Text hat weniger Zeichen als der Index Im Einzelnen können Sie innerhalb einer Prozedur die folgenden Anweisungen notieren85: Ausdruckanweisungen Entscheidungsanweisungen Wiederholungsanweisungen Anweisungen zur Ausnahmebehandlung (try-catch) Sprunganweisungen (return, throw, break und continue) Operatoren und Ausdrücke
3.5 Operatoren und Ausdrücke Ein Operator ist ein Token in einer Programmiersprache, der eine bestimmte Operation auslöst. Zum Beispiel die Addition von zwei Operanden, die rechts und links von einem Operator notiert werden. Oder es werden zwei Operanden miteinander verglichen. Oder es wird mit einem Operator aus einem positiven numerischen Operanden das negative Gegenstück. Operatoren sind allgemein das wichtigste Mittel, um so genannte Ausdrücke formulieren zu können. Die Operatoren in JavaFX sind nun zu einem gewissen Teil identisch mit denen in Java. Genau genommen stimmen die konkreten Zeichen für viele Operatoren mit denen in Java überein, wenn diese in beiden Sprachen identisch vorhanden sind. Allerdings nicht in jedem Fall! JavaFX stellt jedoch überdies einige Operatoren bereit, die es so in Java überhaupt nicht gibt. Das bedeutet aber nicht in jedem Fall, dass es diese Funktionalität in Java nicht gibt. Nur werden dort diverse Operatoren aus JavaFX in Form von Eigenschaften oder Methoden beziehungsweise anderen Sprachkonstrukten zur Verfügung gestellt.
85 Was es mit den verschiedenen Anweisungstypen auf sich hat, wird im Laufe des Kapitels im Detail geklärt.
103
Kapitel 3
> >
>
HINWEIS
Der Grund für die Übereinstimmung von Operatoren in vielen Sprachen ist die gemeinsame Sprachbasis C. Sie werden daher in sehr vielen Programmier- und Skriptsprachen (PHP, JavaScript, Perl, C, C++, C#, etc.) die gleichen Operatoren vorfinden, da sie meist auf C zurückzuführen sind. Für JavaFX muss man jedoch festhalten, dass es diverse Abweichungen von der sonst allgemein üblichen C-Syntax gibt. Und diese Abweichungen sind so gemacht, dass die entsprechenden Operatoren in Java respektive C auch gar nicht als Alternative verwendet werden können (was in anderen Sprachen oft möglich ist – hier gehen meist die C-Varianten als auch – oft sprechendere – alternative Schreibweisen). Auch hier muss ich anmerken, dass sich mir als Java-Programmierer beim ersten Kontakt mit JavaFX die Gründe für diese Abweichungen nicht erschließen wollten. Je länger ich aber darüber nachgedacht habe, desto mehr konnte ich die Überlegung von Sun nachvollziehen86. JavaFX soll sich auch Leuten erschließen, die nicht permanent mit C-lastigen Sprachen programmieren. Bei der Wahl der Token für verschiedene Operatoren ist man zum Teil auf Zeichen der Mathematik ausgewichen (etwa der Operator für Ungleichheit) oder hat versucht, sprechende Token für manche Operatoren zu finden. Es ist garantiert leichter für einen Java-Programmierer, sich diese Token zu merken als für ein Programmierneuling die Token aus C.
JavaFX stellt konkret die nachfolgend besprochenen Operatoren bereit.86
3.5.1 Relationale Operatoren Relationale Operatoren (Vergleichsoperatoren) werden bei Vergleichen von Operanden verwendet. Dies macht man beispielsweise bei Bedingungen in Entscheidungsstrukturen oder Schleifen.87 Operator in JavaFX
Bedeutung
Entsprechender Operator in Java
==
Gleichheit.
==
<>
Ungleichheit. Achtung! In fast allen vergleichbaren Sprachen wird die Variante verwendet, wie sie in Java üblich ist87.
!=
<
Kleiner als
<
>
Größer als
>
<=
Kleiner als oder gleich
<=
>=
Größer als oder gleich
>=
Tabelle 3.3: Die relationalen Operatoren in JavaFX
86 Zumindest glaube ich das. 87 Mir fällt aber Pascal ein, wo wie in JavaFX ebenso der Token <> Verwendung für die Ungleichheit findet.
104
Das Syntaxkonzept von JavaFX Script
3.5.2 Logische Operatoren Die logischen Operatoren (auch Booleschen88 oder Boolean Operatoren genannt) dienen zur Verknüpfung von logischen Ausdrücken, wie sie beispielsweise ein Vergleich liefert. JavaFX versucht diese logischen Operatoren mit möglichst sprechenden Token umzusetzen. Dabei werden Token verwendet, die auch in vielen anderen Sprachen als Ersatz für die C-Syntax verfügbar sind. JavaFX unterstützt aber explizit diese C-Syntax als Alternative nicht und stellt ausschließlich die sprechenden Token zur Verfügung. Operator in JavaFX
Bedeutung
Entsprechender Operator in Java
and
Logisches Und
&&
or
Logisches Oder
||
not
Logische Negation
!
Tabelle 3.4: Die logischen Operatoren in JavaFX
!
!
!
ACHTUNG
Beachten Sie, dass auch bei den logischen Operatoren Groß- und Kleinschreibung von Bedeutung ist. AND ist kein gültiger Token für einen logischen Operator.
3.5.3 Arithmetische Operatoren Die arithmetischen Operatoren dienen zur Berechnung. Hier finden Sie auch keinerlei Abweichungen zwischen JavaFX und Java (beziehungsweise der C-Syntax, aus der diese Operatoren eigentlich stammen). Operator in JavaFX und Java
Bedeutung
+
Addition
-
Subtraktion und Negierung.
*
Multiplikation
/
Division
%
Modulo – der Restwert nach einer Division des linken Operanden durch den rechten Operanden
+=
Addition mit gleichzeitiger Zuweisung
-=
Subtraktion mit gleichzeitiger Zuweisung
*=
Multiplikation mit gleichzeitiger Zuweisung
/=
Division mit gleichzeitiger Zuweisung
Tabelle 3.5: Die arithmetischen Operatoren 88 Nach dem Mathematiker Boole
105
Kapitel 3
Operator in JavaFX und Java
Bedeutung
%=
Modulo mit gleichzeitiger Zuweisung
++
Inkrement
--
Dekrement
Tabelle 3.5: Die arithmetischen Operatoren (Fortsetzung)
Einige der arithmetischen Operatoren dürften aus der Schulmathematik bekannt sein. Andere wiederum nicht. Die arithmetischen Operatoren beinhalten für Einsteiger mit Programmierung sogar einige Tücken. Wir wollen deshalb einige der Operatoren in einem praktischen Beispiel besprechen. Konkret betrifft das vor allem den Modulooperator und die arithmetischen Zuweisungsoperatoren sowie die Inkrement- und Dekrementoperatoren, die wir zuerst noch kurz genauer beschreiben wollen.
Zuweisungsoperatoren Zuweisungsoperatoren werden – wie der Name schon sagt – für die Zuweisung eines Werts zu einer Variablen verwendet. Sie sind als Abkürzung für Kombinationen aus arithmetischer Operation und Zuweisung zu verstehen. Die Anweisung x += 3 entspricht beispielsweise der ausgeschriebenen Form x = x + 3. Oder x /= 2 entspricht in der langen Version x = x / 2.
Modulooperator Der Modulooperator dient zur Rückgabe des Rests einer Division. In Java als auch JavaFX ist der Modulooperator nicht nur für Ganzzahlen definiert (wie etwa in C/C++ oder den meisten anderen Techniken), sondern auch für Fließkommazahlen! Es ist einfach die natürliche Fortsetzung der Operation auf die Menge der Fließkommazahlen.
!
!
!
ACHTUNG
Fließkommaarithmetik ist allgemein extrem heikel wegen potenziellen Rundungsproblemen (das sind Ungenauigkeiten in der Berechnung). Gerade bei Modulorechnungen mit Gleitkommazahlen treten oft Rundungsprobleme auf. Diese Rundungsprobleme sind nicht spezifisch für das Java-Umfeld, sondern treten in fast allen Programmierumgebungen auf.
Inkrement- und Dekrementoperator Der Inkrement- und Dekrementoperator stammen explizit aus C und gehören zu den Operatoren, die man in einer extrem unverständlichen Weise einsetzen kann. Im Grunde ist der Operator sehr einfach und nützlich. Der einstellige Inkrementoperator dient einfach zum Erhöhen des Werts des Operanden um 1.
106
Das Syntaxkonzept von JavaFX Script
Das Problem ist nur, dass die Reihenfolge von Operand und Operator wichtig ist. Wenn der Operator vor dem Operanden steht, erfolgt die Erhöhung des Werts, bevor (!) der Wert dem Operanden zugewiesen wird. Steht er hinter dem Operanden, erfolgt die Erhöhung, nachdem (!) der Wert bereits zugewiesen wurde. Wenn Sie also den Operator in komplexeren zusammengesetzten Ausdrücken verwenden, ist unter Umständen kaum nachvollziehbar, wie sich ein Wert entwickelt. Oder wüssten Sie auf Anhieb, welchen Wert die Variable x am Ende des nachfolgenden Quellcodesegments hat? var x = 9; x += x++ + ++x +x++ + x++ + ++x; Listing 3.12: Syntaktisch ist das korrekt, aber absolut nicht durchschaubar
TIPP
Man sollte den Operator auf jeden Fall nur als einzelne Anweisung verwenden. Zum Beispiel um in Schleifen einen Wert zu erhöhen.
Der einstellige Dekrementoperator erniedrigt vollkommen den Wert des Operanden um 1.
Ein vollständiges Beispiel mit arithmetischen Operatoren Beispiel (operatoren) – beachten Sie die erklärenden Kommentare: 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21
import java.lang.System; import java.lang.Math; // Variablendeklarationen mit Wertzuweisung var x = 17; var y = 3; var z = 4; // Ausgabe verschiedener Berechnungen mit arithemtischen Operatoren System.out.println(x % y); // 17 % 3: 3 * 5 ist 15 – es bleibt der Rest 2 System.out.println(x % z); // 17 % 4: 4 * 4 ist 16 – es bleibt der Rest 1 x += 3; // 17 + 3 – auf den bisherigen Wert von x wird der Wert 3 addiert System.out.println(x); // Ausgabe 20 x /=5; // 20 / 5 – der bisherige Wert von x wird durch den Wert 5 geteilt System.out.println(x); // Ausgabe 4 x %= 3; // 4 % 3: 3 * 1 ist 3 – es bleibt der Rest 1 System.out.println(x); // Ausgabe 1
107
Kapitel 3 22 23 24 25 26 27 28 29
x++; System.out.println(x); // Ausgabe 2 System.out.println(x++); // Ausgabe 2 - danach wird der Wert von x erhöht System.out.println(x); // Ausgabe 3 // Modulo mit Gleitkommazahlen - Achtung Rundungsprobleme! System.out.println(4.2 % 1.7); // Ausgabe 0.8000000000000003
Listing 3.13: Verschiedene arithmetische Operatoren in einem praktischen Beispiel
Das ist die Ausgabe des Beispiels (beachten Sie die erklärenden Kommentare hinter den einzelnen Anweisungen): 2 1 20 4 1 2 2 3 0.8000000000000003
3.5.4 Weitere Operatoren JavaFX stellt nun eine ganze Reihe an weiteren Operatoren zu Verfügung, die auch in den offiziellen Unterlagen von Sun nicht weiter klassifiziert werden. Insbesondere haben viele dieser Operatoren keine direkten Gegenstücke in Java. Dort werden sie allerdings entweder über Sprachkonstrukte oder vielfach Eigenschaften oder Methoden von Objekten abgebildet. Wir wollen die Operatoren hier vollständig auflisten, aber zum Teil werden die nun folgenden Operatoren in den nachfolgenden Abschnitten des Kapitels erst genauer erklärt. Sie benötigen schlicht und einfach für einige Anwendungen ein umfangreicheres Gerüst, was erst noch erarbeitet werden muss.
108
Das Syntaxkonzept von JavaFX Script
Operator in JavaFX
Bedeutung
Entsprechender Operator in Java
sizeof
Die Größe eines Arrays
Kein Gegenstück als Operator
indexof
Die ordinale Position in einer Liste oder einem Array
Kein Gegenstück als Operator
if (Bedingung) then (Anweisungen, wenn Bedingung erfüllt) else (Anweisungen, wenn Bedingung nicht erfüllt)
Ein Bedingungsausdruck beziehungsweise Bedingungsoperator. Bemerkenswert ist einmal, dass diese Token als Operator (mit drei Operanden – ein so genannter triadischer Operator) in JavaFX gewertet werden. Diese Kurzform tritt in anderer Syntax auch in Java auf (siehe die dritte Spalte), wo es einen entsprechenden Operator sowie eine äquivalente Entscheidungsstruktur als Anweisung gibt.
(Bedingung) ? (Anweisungen, wenn Bedingung erfüllt) : (Anweisungen, wenn Bedingung nicht erfüllt)
Was aber noch auffallen sollte, ist das Schlüsselwort then im JavaFX-Operator. In einigen Sprachdialekten gibt es das Anweisungskonstrukt if-then. Diese Konstruktion wurde jedoch in Java und anderen C-basierten Sprachen für die if-Anweisung bewusst nicht gewählt, da das Schlüsselwort then schlicht und einfach überflüssig ist. Und bemerkenswerterweise wird auch die ifAnweisung in JavaFX auf then verzichten. Für den Operator macht then aber trotzdem einen gewissen Sinn, um die Bedingung abzugrenzen. select
Auswahl in einer Liste beziehungsweise einem Datenfeld
Kein Gegenstück als Operator
foreach
Auswahl sämtlicher Elemente in einer Liste beziehungsweise einem Datenfeld
Kein Gegenstück als Operator
Tabelle 3.6: Verschiedene Operatoren in JavaFX und ihre Gegenstücke in Java, falls diese vorhanden sind
109
Kapitel 3
Operator in JavaFX
Bedeutung
Entsprechender Operator in Java
new
Allokieren von Speicherplatz
new
op()
Aufruf einer Funktion/ Operation
Kein Gegenstück als Operator
x.op()
Aufruf einer Funktion/Operation als Mitglied eines Objekts. Das Gegenstück in Java ist in Bezug auf Objektmethoden zu sehen.
x.op()
instanceof
Überprüfung eines Typs eines Objekts
instanceof
this
Eine Selbstreferenz auf das aktu- this elle Objekt
.
Zugriff auf einen Bestandteil eines Objekts. In der zweiten Bedeutung ist es in JavaFX ein Zugriff auf den aktuellen Kontext.
Auch in Java erfolgt der Zugriff auf einen Bestandteil eines Objekts über den Punkt (.). In der Bedeutung als ein Zugriff auf den aktuellen Kontext gibt es kein Gegenstück als Operator in Java.
bind [lazy]
Inkrementelle (lazy) Evaluierung
Kein Gegenstück als Operator
:
Initialisierung einer Variablen beim Deklarieren
Kein Gegenstück als Operator. In Java erfolgt die Wertzuweisung grundsätzlich über den Gleichheitsoperator.
[]
Selektion in einem Datenfeld
[]
format as
Stringformatierung
Kein Gegenstück als Operator
<<>>
Französische Anführungszeichen, um eine beliebige Zeichensequenz als Bezeichner verwenden zu können.
Kein Gegenstück als Operator
{}
Ein Stringausdruck. Das bedeutet, der Ausdruck in dem String wird ausgewertet.
Kein Gegenstück als Operator
(Ausdruck)
Gruppierung
(Ausdruck)
reverse
Dreht eine Liste um.
Kein Gegenstück als Operator
[number1,next..number2]
Numerischer Bereich
Kein Gegenstück als Operator
Tabelle 3.6: Verschiedene Operatoren in JavaFX und ihre Gegenstücke in Java, falls diese vorhanden sind (Fortsetzung)
110
Das Syntaxkonzept von JavaFX Script
Einige der Operatoren können wir erst genauer besprechen, wenn wir wie gesagt erweiterte Techniken in JavaFX besprochen haben. Schauen wir uns dennoch zur Verdeutlichung wieder ein Beispiel mit verschiedenen Operatoren an (operatoren2). Die einzelnen Anweisungen sind umfangreich kommentiert und sollten damit nachvollziehbar sein: 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
import java.lang.System; import java.lang.Math; // Deklaration von verschiedenen Variablen var x = 2; var y = 4; var a = true; var b = false; // Größe eines Arrays - die Ausgabe ist 2 System.out.println(sizeof [x, y]); // Prüfung, ob die Variable a den Wert true hat. Da dem so ist, // ist die Ausgabe 2. Die Anweisung hinter then wird ausgewählt. System.out.println(if a then x else y); // Ein Testwert q wird im Array gesucht. Bedingung ist, dass q > 3 ist // Die Ausgabe ist deshalb 4 – der Wert von y System.out.println(select q from q in [x, y] where q > 3); // Ausgabe aller Werte in dem Array, die kleiner als der Wert 3 sind. // Die Ausgabe ist 2 – der Wert der Variablen x System.out.println(foreach(q in [x, y] where q < 3) q); // Aufruf einer Klassenmethode – Das Maximum von x und y // - die Ausgabe ist 4. Der Wert von y System.out.println(Math.max(x, y)); // Für ein Stringobjekt wird eine Methode aufgerufen. Diese konvertiert // den Inhalt in Großbuchstaben. Die Ausgabe ist ABC System.out.println("abc".toUpperCase()); // Überprüfung, ob x eine Variable vom Typ Number ist. // Die Ausgabe ist true System.out.println(x instanceof Number);
Listing 3.14: Verschiedene Operatoren im Einsatz
111
Kapitel 3
Die Ausgabe sieht wie folgt aus: 2 2 4 2 4 ABC true
3.5.5 Ausdrücke Ausdrücke sind allgemein eines der wichtigsten Stilmittel in der Programmierung. Sie sind das, was einen Wert in einer Programmierung repräsentiert. Sie drücken einen Wert entweder direkt (durch ein Literal) oder durch eine Berechnung im weiteren Sinn aus. Ausdrücke können Konstanten, Variablen, Literale, Schlüsselwörter, Operatoren und andere Ausdrücke beinhalten Wir haben in unseren bisherigen Beispielen natürlich schon diverse Ausdrücke verwendet. In diesem Abschnitt wollen wir die Ausdrücke von JavaFX genauer untersuchen, denn die Thematik passt hervorragend zu Operatoren. Man kann Ausdrücke am einfachsten folgendermaßen definieren: Ausdrücke sind das Ergebnis der Verbindung von Operanden und Operatoren über die syntaktischen Regeln der Sprache. Ausdrücke werden also für die Durchführung von Operationen (Manipulationen) an Variablen oder Werten verwendet. Dabei sind Spezialfälle wie arithmetische Konstanten beziehungsweise Literale kein Widerspruch.
Die Bewertung von Ausdrücken Ausdrücke kommen selbstverständlich auch über komplizierte Kombinationen von Operatoren und Operanden vor. Deshalb muss ein ausführendes System diese Kombinationen bewerten, also eine Reihenfolge festlegen, wie diese komplexeren Ausdrücke auszuwerten sind. Das ist in der menschlichen Logik nicht anders, etwa die Punkt-vorStrich-Rechnung in der Mathematik. Überhaupt lässt sich die Bewertung von Ausdrücken in den meisten Skript- und Programmiersprachen durch die Auswertung von Ausdrücken in der Mathematik intuitiv herleiten.
112
Das Syntaxkonzept von JavaFX Script
Eine Bewertung von Ausdrücken basiert auf drei Grundbegriffen, die in nahezu allen Programmier- und Skriptsprachen analog umgesetzt werden: Alle arithmetischen Ausdrücke werden bei einer Verarbeitung von links nach rechts ausgewertet. Wenn Operatoren gleicher Priorität in einem Ausdruck mehr als einmal auftauchen – wie beispielsweise der +-Operator bei dem Ausdruck 1 + 2 + 3 + 4 + 5 –, dann wird der am weitesten links erscheinende Ausdruck (1 + 2) zuerst ausgewertet, gefolgt von dem rechts daneben usw. Dieses Verhalten nennt man Operatorassoziativität. Der so genannte Operatorvorrang bedeutet die Berücksichtigung der Priorität von Operatoren. Wenn Sie einen Ausdruck mit unterschiedlichen Operatoren haben, muss das System entscheiden, wie Ausdrücke ausgewertet werden. Dazu wird zuerst der gesamte Ausdruck analysiert. Anschließend wird der am höchsten priorisierte Operator zuerst. Runde Klammern haben die höchste Priorität, weshalb jeder Ausdruck in Klammern zuerst ausgewertet wird. Als dritten Begriff muss man die so genannte Bewertungsreihenfolge beachten. Die Bewertungsreihenfolge bewertet im Gegensatz zum Operatorvorrang die Operanden. Die Bewertungsreihenfolge legt fest, welche Operatoren in einem Ausdruck zuerst benutzt werden und welche Operanden zu welchen Operatoren gehören. Außerdem dienen die Regeln für die Bewertungsreihenfolge zur Festlegung, wann Operanden ausgewertet werden.
3.5.6 Stringliterale und Stringausdrücke in JavaFX Wie schon erwähnt, können Sie in JavaFX eine Zeichenkette sowohl in einfache als auch doppelte Hochkommata einschließen. Und wie auch beispielsweise in PHP werden Zeichenketten in doppelten und einfachen Hochkommata vom System bei gewissen Situationen unterschiedlich behandelt.
Auswertung von Ausdrücken in Strings Wenn Sie beispielsweise den Bezeichner einer Variablen in eine Zeichenkette mit doppelten Hochkommata notieren und diesen in geschweifte Klammern {} einschließen, wird der Ausdruck ausgewertet. Sie erhalten in dem resultierenden String den Wert der eingeschlossenen Variablen beziehungsweise eines Ausdrucks. Dabei sind Sie für die Art der ausgewerteten Variable nicht auf Zeichenketten beschränkt. Bei einer Zeichenkette in einfachen Hochkommata finden Sie dieses Verhalten nicht89.
89 In PHP kennt man ein ähnliches Verhalten.
113
Kapitel 3
Machen wir uns das in einem Beispiel deutlich (Zeichenketten): 01 02 03 04 05 06 07 08 09 10 11
import java.lang.System; var var var var var
name wert s1 = s2 = s3 =
= 'Trillian'; = 5; "Hallo {name}"; // Zeichenkette mit doppelten Hochkommata 'Hallo {name}'; // Zeichenkette mit einfachen Hochkommata "Hallo {wert}"; // Zeichenkette mit doppelten Hochkommata
Die Ausgabe ist folgende: Hallo Trillian Hallo {name} Hallo 5 TIPP
Diese Möglichkeit zum Auswerten von Ausdrücken in Zeichenketten erleichtert für Einsteiger den Umgang mit Variablenwerten und Textausgaben und ist deshalb verführerisch. Ich denke aber, viele erfahrene Umsteiger aus anderen Sprachen werden dennoch – am Anfang – die traditionelle Version des Zusammensetzens einer Zeichenkette vorziehen. Und sei es nur, um sich keinen Programmierstil anzugewöhnen, der in anderen Sprachen – insbesondere Java – nicht funktioniert. Das Beispiel von eben könnte man auch so schreiben, was zwar auf den ersten Blick etwas umständlicher erscheint, von der Struktur dann aber auch in anderen Sprachen funktioniert (zeichenketten2): // String-Variable wird mit concat() an String angehängt var s1 = "Hallo ".concat(name); var wert = 5; // Numbervariable wird mit toString()in String umgewandelt und mit // concat() an String angehängt var s3 = "Hallo ".concat(wert.toString()); Listing 3.16: Die »saubere« Variante zur Verwertung von Variablenwerten in Verbindung mit einem String
Dennoch habe ich mich – nachdem ich am Anfang diese Auswertung von Ausdrücken in Strings gar nicht gemocht habe – mehr und mehr damit anfreunden können. Und zwar je mehr ich insbesondere dynamische grafische Oberflächen mit JavaFX erstellt habe. Hier ist die Möglichkeit der Auswertung von Ausdrücken innerhalb eines Strings für einige Vorgänge schlicht und einfach genial.
114
Das Syntaxkonzept von JavaFX Script
In JavaFX kann der eingeschlossene Ausdruck selbst wieder Strings in doppelten Hochkommata enthalten, worin sogar weitere Ausdrücke eingeschlossen sein können.
> >
>
HINWEIS
So etwas ist in mir bekannten vergleichbaren anderen Sprachen nur mit ausdrücklicher Markierung der eingeschlossenen Hochkommata möglich.
Das nachfolgende Beispiel funktioniert in JavaFX: 01 02 03 04 05 06
import java.lang.System; var antwort = true; var s = "Die Antwort ist {if antwort then "Ja" else "Nein"}."; // s hat nun den Wert 'Die Antwort ist Ja' System.out.println(s);
Listing 3.17: Verwenden von eingeschlossenen doppelten Hochkommata
Nach dem Import in Zeile 1 wird in Zeile 3 eine Boolesche Variable antwort eingeführt und mit dem Wert true versehen (eine indirekte Festlegung des Datentyps über den Datentyp des Literals). In Zeile 4 wird ein Ausdruck innerhalb eines Strings ausgewertet – in diesem Fall der Bedingungsoperator. Da der Wert der Bedingung in Zeile 3 als true festgelegt wird, wird die Anweisung hinter then ausgewählt und der Wert in den umgebenden String eingefügt. Dies ist der String mit dem Inhalt "Ja". Also ein Stringliteral, das in doppelte Hochkommata eingeschlossen ist. Das ist die Ausgabe des Beispiels: Die Antwort ist Ja.
Zeilenumbrüche in Strings Im Gegensatz zu Java können in JavaFX Zeichenketten Zeilenumbrüche enthalten, wenn sie in doppelte Hochkommata eingeschlossen sind. Beispiel: 01 var s = "Die 02 Antwort ist 03 42"; Listing 3.18: Eine Zeichenkette geht über mehrere Zeilen
115
Kapitel 3 90
> >
>
HINWEIS
Ehrlich gesagt hat es mir beim ersten Kontakt mit der Möglichkeit, eine Zeichenkette so auf mehrere Zeilen aufzuteilen, regelrecht gegraut. Aber auch die Auswertung von Ausdrücken in Strings sowie das Einschließen von Hochkommata gleichen Typs in einen String ohne explizite Markierung hat mich ganz kribbelig gemacht. Solche Sachen gehören in fast allen von mir sonst verwendeten Programmiersprachen90 zu den klassischen Anfängerfehlern, die ich meinen Schulungsteilnehmern austreiben muss. Und nun das – eine Sprache, in der so etwas keinen Fehler mehr darstellt. Aber um es noch einmal zu erwähnen – mein Aha-Erlebnis war die Erstellung von grafischen Oberflächen mit JavaFX. Hier eröffnen diese ungewohnten Verhaltensweisen beim Erstellen von Quellcode einfach geniale Möglichkeiten und vereinfachen die Erstellung immens.
3.6 Anweisungen Anweisungen sind in einer Programmier- oder Skriptsprache solche Syntaxstrukturen, die bestimmte Dinge aktiv ausführen. Anweisungen werden in der Regel einfach der Reihe nach ausgeführt. Ausnahmen sind Kontrollflussanweisungen oder Ausnahmeanweisungen. Sie werden aufgrund eines besonderen Effekts ausgeführt. Grundsätzlich unterteilt man Anweisungen nach ihrer Art.
> >
>
HINWEIS
Beachten Sie, dass wir die meisten Anweisungsformen in unseren bisherigen Beispielen schon gesehen haben.
3.6.1 Blockanweisung Eine Blockanweisung ist einfach eine Zusammenfassung von mehreren Anweisungen zu einer Blockstruktur. In Java und JavaFX erledigen das die geschweiften Klammern, wie wir schon häufiger gesehen haben. So weit lesen Sie hier auch nichts Neues. Aber das ist neu. Ein Anweisungsblock hat in Java und JavaFX seinen eigenen Geltungsbereich für die in ihm enthaltenen Anweisungen. Das bedeutet, dass in einigen Blockstrukturen lokale Variablen in diesem Block deklariert werden können, die außerhalb dieses Blocks nicht verfügbar sind und deren Existenz erlischt, wenn der Block ausgeführt wurde – beispielsweise so genannte schleifenlokale Variablen, die nur innerhalb einer Schleife91 zur Verfügung stehen.
90 Mit Ausnahme von PHP – auch da kann man fast genauso viele schlimme ;-) Sachen machen. 91 Sollten Sie noch nie etwas von Schleifen gehört haben – stellen Sie sich diese bis auf weiteres einfach als eine Wiederholung von Anweisungen vor.
116
Das Syntaxkonzept von JavaFX Script
Schauen wir uns dazu ein Beispiel (blockanweisungen) an, das auf Schleifen vorgreift (die werden aber unmittelbar in der Folge erläutert): 01 02 03 04 05 06 07 08
import java.lang.System; var x = 1; for(i in [0..5]) { var x = i; System.out.println(x); } System.out.println(x);
Listing 3.19: Ein Block mit einer schleifenlokalen Variablen
In Zeile 3 wird eine global gültige Variable x eingeführt. Diese bekommt direkt bei der Deklaration den numerischen Wert 1 zugewiesen. In der folgenden Schleife wird ebenfalls mit einer Variable mit dem gleichen Bezeichner x gearbeitet. Der zugehörige Block erstreckt sich von Zeile 4 bis 7. Diese schleifenlokale Variable bekommt in Zeile 5 jeweils den Wert der Zählvariablen i zugewiesen. In Zeile 6 wird der jeweilige Wert von x ausgegeben (von 0 bis 5). Das ist der Wert, der in der Schleife zugewiesen wird. In Zeile 8 wird anschließend der Wert der global definierten Variable x ausgegeben. Hätte die Variable x in dem Block keinen eigenen Gültigkeitsbereich, müsste der Wert dieser Variablen durch die Zuweisungen in der Schleife verändert worden sein. Die Ausgabe beweist aber, dass dem nicht so ist. Der Wert der global definierten Variable x ist weiter 1: 0 1 2 3 4 5 1
3.6.2 Deklarationsanweisung Eine Deklarationsanweisung ist eine Anweisung zur Einführung einer Variabeln, einer Funktion, einer Operation, einer Klasse oder eines Objekts. Dazu soll an dieser Stelle nicht mehr ausgeführt werden, da wir Deklarationsanweisungen bei den jeweiligen Themen direkt besprechen beziehungsweise auch schon besprochen haben.
117
Kapitel 3
3.6.3 Ausdrucksanweisung Ausdrucksanweisungen sind der offizielle Name für die folgenden Anweisungsarten, die wir an anderen Stellen genauer behandeln beziehungsweise schon behandelt haben: Zuordnungen Inkrement Dekrement Aufrufe von Methoden beziehungsweise Funktionen und Operationen Zuweisungen Alle Ausdrucksanweisungen müssen in JavaFX wie in Java mit einem Semikolon beendet werden und eine Ausdrucksanweisung wird immer vollständig durchgeführt, bevor die nächste Anweisung ausgeführt wird.
3.6.4 Leere Anweisung Es gibt in Java auch eine leere Anweisung. Sie besteht nur aus einem Semikolon und dient als Platzhalter. In JavaFX gibt es diese leere Anweisung nicht! Mit anderen Worten: Ein einzelnes Semikolon, das nicht eine Anweisung beendet, wird in JavaFX als Fehler gewertet.
3.6.5 Auswahlanweisung Eine Auswahlanweisung ist eine Kontrollflussanweisung. Mit einer Auswahlanweisung sucht man einen von mehreren möglichen Kontrollflüssen eines Programms beziehungsweise Skripts heraus. Sowohl Java als auch JavaFX unterstützt verschiedene Auswahlanweisungen. Allerdings sind diverse Unterschiede zu beachten. Insbesondere kennt JavaFX beispielsweise keine switch-case-Anweisung. Das ist jedoch kein schlimmer Verlust, denn mit den verbleibenden if- beziehungsweise if-else-Anweisungen kann man alles machen, was zur Steuerung des Programmflusses notwendig ist.
Die if- und die if-else-Anweisung Eine if-Anweisung testet eine Boolesche Variable oder einen Ausdruck. Wenn die Boolesche Variable oder der Ausdruck den Wert true hat, wird die nachstehende Anweisung oder der nachfolgende Anweisungsblock ausgeführt. Ansonsten wird die nachstehende Anweisung oder der nachstehende Anweisungsblock ignoriert und mit dem folgenden Block beziehungsweise der folgenden Anweisung fortgefahren.
118
Das Syntaxkonzept von JavaFX Script
Eng verwandt ist die if-else-Anweisung, die genau genommen nur eine Erweiterung der if-Anweisung ist. Sie hat nur noch einen zusätzlichen else-Teil. Dieser else-Teil wird dann ausgeführt, wenn der Boolesche Test im if-Teil der Anweisung den Wert false ergibt.
!
!
!
ACHTUNG
Im Grunde unterscheiden sich Java und JavaFX nicht bezüglich der if- beziehungsweise if-elseAnweisung. Nur müssen Sie in JavaFX die Anweisungen zwingend in Blöcke notieren. In Java kann man eine einzelne Anweisung auch ohne umgebende geschweifte Klammern notieren, obwohl davon dringend abzuraten ist. Zu leicht vergisst man bei einer späteren Erweiterung um weitere Anweisungen die dann notwendigen Klammern. So gesehen ist der Zwang in JavaFX eine positive Entwicklung.
import java.lang.System; var x = 4; if(x == 3) { System.out.println("a"); } else { System.out.println("b"); }
Listing 3.20: Eine einfache if-else-Anweisung
Die Ausgabe des Beispiels ist b.
3.6.6 Schleifen Schleifen dienen allgemein der Wiederholung von Anweisungen. Auch bei Schleifen muss man zwischen Java und JavaFX diverse Unterschiede beachten.
Die while-Anweisung Die while-Anweisung sieht schematisch wie folgt aus: while(Bedingung) Block Listing 3.21: Schema für eine while-Schleife
Wenn der in der Bedingung überprüfte Ausdruck nicht von Anfang an den Wert true liefert, wird der Block niemals ausgeführt. Man nennt dies eine kopfgesteuerte oder abweisende Iterationsanweisung.
119
Kapitel 3
Wenn der Test in der Bedingung hingegen true liefert, dann wird dieser Codeblock so lange wiederholt, bis der Test nicht mehr true liefert. Alternativ kann durch eine Sprunganweisung (siehe Seite 125) die Kontrolle an eine Anweisung außerhalb der Schleife weitergegeben werden.
!
!
!
ACHTUNG
Im Grunde unterscheiden sich Java und JavaFX auch nicht bezüglich der while-Anweisung. Nur müssen Sie wie bei der if-Anweisung in JavaFX die Anweisung nach der Bedingung zwingend in einen Block notieren. In Java kann man eine einzelne Anweisung auch ohne umgebende geschweifte Klammern notieren, obwohl davon – wie bei der if-Anweisung zu ausgeführt – dringend abzuraten ist.
Beispiel (whileanweisung): 01 02 03 04 05 06 07
import java.lang.System; var i = 0; while (i < 10) { System.out.println("i = {i}"); i++; }
Listing 3.22: Eine while-Schleife
Die Zählvariable i wird in Zeile 3 eingeführt und mit dem Wert 0 initialisiert. In Zeile 4 wird überprüft, ob der Wert der Zählvariablen kleiner als 10 ist (while (i < 10) {). Wenn das der Fall ist, wird der Wert von i ausgeben. Dabei wird der Wert von i in einem String in geschweifte Klammern notiert und damit ausgewertet. In Zeile 6 wird der Wert der Zählvariablen mit dem Inkrementoperator erhöht (i++;). Das ist die Ausgabe: i=0 i=1 i=2 i=3 i=4 i=5 i=6 i=7 i=8 i=9
120
Das Syntaxkonzept von JavaFX Script
!
!
!
ACHTUNG
Allgemein sind Schleifen Kandidaten für so genannte Endlosschleifen. Das sind Schleifen, die nie beendet werden und immer wieder die darin notierten Anweisungen ausführen. Eine whileSchleife ist ein besonders »guter« Kandidat für eine solche – ungewollte – Endlosschleife. Leicht übersieht man im Inneren der Schleife eine Situation zu schaffen, in der die Bedingung zum Durchlaufen der Schleife nicht mehr erfüllt ist, oder durch einen Sprung die Schleife zu verlassen. Dann hängen Sie in einer Endlosschleife.
Die for-Anweisung Diese Iterationsanweisung ist kopfgesteuert und fasst bereits im Schleifenkopf alle relevanten Anweisungen zur Steuerung der Schleife zusammen. Deshalb ist diese Iterationsanweisung bei den meisten Programmierern die beliebteste Schleifenform. Nun hat Sun für die for-Anweisung in JavaFX aber nicht die Syntax gewählt, wie sie in Java und allen C-basierenden Sprachen verwendet wird. Diese steht auch gar nicht mehr zur Verfügung! Stattdessen verwendet man in JavaFX eine Syntax, die sonst eigentlich nur in einer Spezialform der for-Anweisung – der foreach-Anweisung – Verwendung findet. Der Kopf der for-Anweisung in JavaFX verwendet sogar die gleiche Syntax wie der foreach-Operator. Angeblich soll diese Version der Syntax einer for-Schleife für Einsteiger leichter zu verstehen sein92, aber das ist wahrscheinlich nicht der wirkliche Grund für diesen Umstieg gegenüber der Java-Syntax. Diese Form der Schleife minimiert die Gefahr von ungewollten Endlosschleifen. Eine einfache for-Anweisung sieht in JavaFX vom Schema her wie folgt aus: for (Zählvariable in [Beginn Wertebereich .. Ende Wertebereich]) Block Listing 3.23: Schema der Syntax für eine for-Anweisung
Beim ersten Schleifendurchlauf wird die Zählvariable auf den Anfangswert des Wertebereichs gesetzt. Vor jedem weiteren Schleifendurchlauf wird überprüft, ob sich die Zählvariable im dem angegebenen Wertebereich befindet. Während eines Schleifendurchlaufs wird die Zählvariable automatisch um den Wert 1 erhöht, wenn der Endwert größer als der Startwert ist. Ist der Endwert jedoch kleiner als der Startwert, wird die Zählvariable während jedes Schleifendurchlaufs automatisch um den Wert 1 erniedrigt. Das entspricht also einem Rückwärtszählen. Beispiel (den Quelltext als auch die nachfolgenden Ausführungen zu der for-Schleife finden Sie im Ordner foranweisung):
92 Ich persönlich ziehe aber die C-Syntax in der Regel vor.
import java.lang.System; // Ausgabe von 0 bis 5 for (i in [0..5]) { System.out.println("i = {i}"); } // Ausgabe von 3 bis 5 for (i in [3..5]) { System.out.println("i = {i}"); } // Ausgabe von 5 bis 2 for (i in [5..2]) { System.out.println("i = {i}"); }
Listing 3.24: Eine einfache for-Anweisung
Die erste Schleife wird sechs Mal durchlaufen und gibt dabei jeweils den aktuellen Wert der Zählvariablen aus. Beachten Sie in Zeile 15 die Auswertung der Variable i über {i} innerhalb des Strings. Die zweite Schleife beginnt mit dem Startwert 3 und die dritte Schleife erniedrigt jeweils die Zählvariable. Die for-Anweisung in JavaFX wurde nun um ein paar mehr oder weniger nützliche Tricks erweitert. In der klassischen Version einer for-Anweisung kann man die Schrittweite (also die Größe der Werterhöhung der Zählvariablen) flexibel verändern. Es gibt zwar kaum einen sinnvollen Grund, warum man das tun sollte93, aber in der Version von JavaFX hat man dennoch diese Möglichkeit vorgesehen. Dazu kommt aber eine doch recht eigenwillige Syntax zum Einsatz, die so auch allgemein bei Datenfeldern verwendet werden kann (siehe Seite 136). Am Beginn des Wertebereichs gibt man zwei Zahlen an, die man mit einem Komma trennt. Die Differenz zwischen den Zahlen gibt die Schrittweite an. Beispiel: 01 import java.lang.System; 02 03 for (i in [1,4..10]) { 04 System.out.println("i = {i}"); 05 } Listing 3.25: Eine andere Schrittweite für die Schleife
93 Beachten Sie dazu den nachfolgenden Hinweis.
122
Das Syntaxkonzept von JavaFX Script
Das Beispiel gibt die Werte 1, 4, 7 und 10 aus, weil die Schrittweite 3 ist (4 – 1). Ein weiterer Trick in einer for-Anweisung ist eine genauere Angabe, wie die Zählvariable sich verhalten soll. Dazu kommen so genannte Filter zum Einsatz, die der SQLSyntax entsprechen und analog bei Arrays Verwendung finden (siehe dazu Seite 133)94. Sie werden mit dem Schlüsselwort where eingeleitet. Beachten Sie das nachfolgende Beispiel: 01 02 03 04 05 06
import java.lang.System; // Ausgabe aller geraden Zahlen über einen Filter for (i in [0..10] where i % 2 == 0) { System.out.println("i = {i}"); }
Listing 3.26: Einsatz eines Filters
Mit diesem Beispiel werden alle geraden Zahlen von 0 bis 10 ausgegeben.
> >
>
HINWEIS
So interessant die Abarten eine for-Schleife auch erscheinen mögen – man kommt bei einer forAnweisung (und jeder Schleife) immer mit der Schrittweite 1 ohne weitere Angaben aus. Selbst wenn man auf den ersten Blick vielleicht eine andere Schrittweite benötigt (etwa um nur alle geraden Zahlen zu durchlaufen), kann man durch einfaches Anpassen der Anweisungen im Körper der Schleife immer auf Basis einer Schrittweite 1 agieren. Auch die Möglichkeit des Reduzierens der Zählvariablen oder der Einsatz von Filtern für die Zählvariable ist deshalb im Grunde vollkommen überflüssig. Solche »Tricks« widersprechen sogar modernen Tendenzen in der Programmierung, die Programmierer zu einem »langweiligen« Programmierstil zu bewegen versuchen. Langweilig wäre beispielsweise, wenn alle for-Schleifen im Header exakt gleich aussehen (bis auf den wirklichen Endwert). Damit wird die Lesbarkeit und Wartbarkeit von Quellcode massiv erhöht, was letztendlich in besseren, stabileren Programmen mündet. Etwas anderes ist es, wenn man die Sache aus Sicht eines Arrays (siehe Seite 130) betrachtet. Die Angabe in den eckigen Klammern bei einer for-Schleife ist ein Array. Und hier erleichtert JavaFX mit diesen Möglichkeiten den Umgang doch erheblich. Wie schon an verschiedenen anderen Stellen sollten sich meines Erachtens erfahrene Programmierer in Geduld üben und nicht gleich Ansätze von JavaFX verteufeln, die scheinbar professionellen Regeln widersprechen. Wenn man JavaFX verinnerlicht hat, zeigen sich an vielen Stellen sehr intelligente Ideen hinter scheinbar unprofessionellen Ansätzen.
94 Genau genommen handelt es sich bei der Angabe des Wertebereichs einer for-Anweisung auch um ein Array.
123
Kapitel 3
Sie können in einer for-Anweisung nun auch mehrere Zählvariablen parallel verwenden. Die verschiedenen Zählvariablen werden dabei getrennt erhöht. Dieses Konstrukt ist ein Ersatz für verschachtelte for-Schleifen und aus meiner Sicht eine der nützlichsten Erweiterungen einer einfachen for-Schleife. Beispiel: 01 import java.lang.System; 02 03 for (i in [0..2], j in [0..2]) { 04 System.out.println("i = {i}"); 05 System.out.println("j = {j}"); 06 } Listing 3.27: Eine spezielle JavaFX-Variante von verschachtelten for-Schleifen
In dem Beispiel wird zuerst die Zählvariable i auf den Wert 0 gesetzt und anschließend der Wertebereich für j durchlaufen. Dann wird i erhöht und erneut der Wertebereich von j durchlaufen usw. Die Ausgabe ist das: i=0 j=0 i=0 j=1 i=0 j=2 i=1 j=0 i=1 j=1 i=1 j=2 i=2 j=0 i=2 j=1 i=2 j=2
124
Das Syntaxkonzept von JavaFX Script
Die do- und die do-later-Anweisung Die do-Anweisung (oder auch do-while-Anweisung genannt) in Java testet eine Boolesche Variable oder einen Ausdruck – aber erst am Ende eines Blocks, weshalb man von einer annehmenden oder fußgesteuerten Iterationsanweisung spricht. Damit wird der Codeblock innerhalb der do-Anweisung auf jeden Fall mindestens einmal ausgeführt. Das Tückische in JavaFX ist nun aber, dass die do-Anweisung dort nicht diese Funktionalität hat, sondern sowohl eine andere Syntax als auch eine gänzlich anders gelagerte Anwendung. Es ist keine Schleife im klassischen Sinn und die Thematik in Verbindung mit der do-Anweisung ist alles andere als trivial. Sie wird im Umfeld des so genannten Multithreadings eingesetzt. Ebenso die verwandte Anweisung do later. Wir werden die do-Anweisung, wie sie in JavaFX realisiert ist, und die do-later-Anweisung in dem Kapitel 7 zu den erweiterten JavaFX-Techniken besprechen.
3.6.7 Sprunganweisung So genannte Sprunganweisungen geben in einem Programm oder Skript den Programmfluss bei ihrem Aufruf unmittelbar entweder an den Anfang oder das Ende des derzeitigen Blocks weiter. Java und JavaFX kennen vier Arten von Sprunganweisungen, die fast gleich implementiert sind: break continue return throw Die break- und die return-Anweisung haben wir im Laufe des Buchs ja bereits mehrfach behandelt. Aber dennoch gibt es auch dazu noch einige explizite Feinheiten sowie auch Unterschiede zu Java zu beachten.
Die return-Anweisung Mit der return-Anweisung verlassen Sie eine Funktion oder Operation und liefern einen Rückgabewert, wenn Sie nach dem Schlüsselwort return einen solchen Wert (als Literal oder berechnet) notieren. Letzteres bedeutet, Sie können auch die return-Anweisung notieren, ohne danach einen Rückgabewert zu schreiben. Das geht zumindest bei einer Operation beziehungsweise Prozeduren. Sie notieren dann nur direkt ein Semikolon nach dem Schlüsselwort return. Allerdings können Sie auch bei einer Operation einen Rückgabewert notieren (also einen Wert hinter return notieren).
125
Kapitel 3
!
!
!
ACHTUNG
Der Aufruf von return ohne Rückgabewert geht nicht bei Funktionen. Hier müssen Sie immer einen Rückgabewert notieren.
import java.lang.System; function add(x, y) { // Rückgabewert der Funktion return x + y; } operation add2(x, y) { System.out.println(x + y); // Aufruf von return oder Rückgabewert – das geht // in einer Operation return ; } System.out.println(add(7,1)); add2(4,5);
Listing 3.28: Die Verwendung von return in einer Funktion und einer Prozedur
!
!
!
ACHTUNG
Es ist leider durch eine unglückliche Kodierung des Quelltexts möglich, Codezeilen zu schreiben, die nie erreicht werden können. Das kann passieren, wenn Sie in einer Funktion oder Operation nach einer return-Anweisung, die auf jeden Fall ausgeführt wird (also nicht in Abhängigkeit von einer Bedingung), weitere Anweisungen notieren. Dies nennt man dann unerreichbaren Code (unreachable Code). Solcher Code ist zwar eigentlich nicht schädlich in dem Sinne, dass er etwas Falsches tut (im Gegenteil – er wird ja gar nicht ausgeführt), aber wenn man sich darauf verlässt, dass bestimmte Codezeilen ausgeführt werden, und sie werden einfach nicht erreicht, kann der Schaden mindestens genauso groß sein. Der Java-Compiler bemerkt solche Konstruktionen mit unerreichbarem Code glücklicherweise fast immer und erzeugt einen Fehler zur Kompilierzeit. Soweit die gute Nachricht! Die schlechte Nachricht – der JavaFX-Interpreter bemerkt unerreichbaren Code nicht! Zumindest nicht in der Version, die dem Buch zugrunde liegt. Und das führt in der Tat dazu, dass eine JavaFX-Applikation mit unerreichbarem Code zum Laufen gebracht werden kann.
Listing 3.29: Das Beispiel funktioniert trotz unerreichbarem Code
Zeile 5 bewirkt, dass die Operation verlassen wird. Zeile 7 wird niemals erreicht. Das ist unerreichbarer Code. Es ist bedauerlich, dass (derzeit) in JavaFX einer der intelligentesten Sicherheits- und Stabilitätsmechanismen nicht funktioniert. Die Verantwortung für die Vermeidung solcher Fehlersituationen liegt also wieder rein beim Programmierer.
Die break-Anweisung Die break-Anweisung in JavaFX verhält sich wie die gleiche Anweisung in Java. Nur werden keine Sprünge an Labels (bezeichnete Sprungmarken) unterstützt95. Wie in Java muss die break-Anweisung im Körper einer Schleife verwendet werden. Der Programmfluss verlässt beim Auftreten der break-Anweisung unmittelbar die Schleife. Beispiel (breakanweisung): 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15
import java.lang.System; operation breaktest(y) { System.out.println("Start"); for (i in [0..5]) { if (i > y) { System.out.println("Abbruch vor Ende des Wertebereichs"); break; } System.out.println(i); } System.out.println("Ende"); } breaktest(7); breaktest(3);
Listing 3.30: Die Verwendung von break 95 Das ist aber keine wesentliche Einschränkung, denn Sprünge an Label werden nicht viel eingesetzt. Zumal solche gesteuerten Sprungadressen an Zeiten unseligen Spaghetticodes mittels des GotoBefehls und Konsorten erinnert (obgleich benannte Sprungadressen in Java beileibe nicht so schlimm sind).
127
Kapitel 3
In dem Beispiel wird die break-Anweisung aufgerufen, wenn die Zählvariable i der for-Schleife größer als der Wert der Variable y ist, der als Übergabewert beim Aufruf der Prozedur angegeben wird. Das bedeutet, wenn der Wert des Parameters größer als 5 ist, wird die Schleife nicht zu Ende abgearbeitet, sondern vorher mit break abgebrochen. Die Ausgabe des Aufrufs in Zeile 15 zeigt das. Das ist die Ausgabe des Beispiels: Start 0 1 2 3 4 5 Ende Start 0 1 2 3 Abbruch vor Ende des Wertebereichs Ende
!
!
!
ACHTUNG
Leider kann man auch mit der break-Anweisung in JavaFX unerreichbaren Code erzeugen.
Die continue-Anweisung Die continue-Anweisung kommt nur in Zusammenhang mit Iterationsanweisungen zum Einsatz und bricht dort einen Schleifendurchlauf ab. Durch continue wird also im Gegensatz zu break oder return nicht die gesamte Schleife abgebrochen, sondern es wird nur der aktuelle Schleifendurchlauf unterbrochen und zum Anfang der Schleife zurückgekehrt. Die continue-Anweisung in JavaFX verhält sich wie die gleiche Anweisung in Java. Nur sind auch hier keine Sprünge an Labels möglich.
import java.lang.System; operation continuetest() { System.out.println("Ausgabe ganze Zahlen"); for (i in [0..20]) { if (i % 2 <> 0) { System.out.println("Ungerade Zahl"); continue; } System.out.println(i); } } continuetest();
Listing 3.31: Die Ausgabe von ganzen Zahlen mit continue
In der Zeile 6 wird überprüft, ob die Zählvariable i modulo dem Wert 2 von 0 verschieden ist. Wenn dem so ist, muss eine ungerade Zahl vorliegen. Dann wird ein reiner Text ausgegeben und mit continue der nächste Schleifendurchlauf gestartet. Das ist die Ausgabe des Beispiels: Ausgabe ganze Zahlen 0 Ungerade Zahl 2 Ungerade Zahl 4 Ungerade Zahl 6 Ungerade Zahl 8 Ungerade Zahl 10 Ungerade Zahl 12
129
Kapitel 3
Ungerade Zahl 14 Ungerade Zahl 16 Ungerade Zahl 18 Ungerade Zahl 20
Die throw-Anweisung Die throw-Anweisung ist wesentlicher Bestandteil des Konzepts der Ausnahmebehandlung in JavaFX. Wir werden sie explizit in Kapitel 7 bei den erweiterten JavaFXTechniken besprechen.
3.6.8 Die try-Anweisung Die try-Anweisung ist wie die Anweisung throw wesentlicher Bestandteil des Konzepts der Ausnahmebehandlung. Wir werden auch diese explizit in Kapitel 7 zu den erweiterten JavaFX-Techniken besprechen.
3.7 Arrays und der Operator [] Kommen wir nun zu einem Thema, das in JavaFX aus meiner Sicht für eine Programmier- beziehungsweise Skriptsprache teilweise recht ungewöhnlich – und sehr effektiv und intelligent96 – umgesetzt wurde. An dieser Stelle berühren wir eine der wichtigsten Variablenstrukturen in vielen Programmiersprachen – die so genannten Arrays oder Datenfelder. Diese Strukturen werden in JavaFX (wie auch Java und vielen anderen Programmiersprachen) mit den eckigen Klammern gekennzeichnet. Ungewöhnlich ist in JavaFX jedoch die Verwendung der eckigen Klammern bei einer Initialisierung, wie Sie sehen werden. Und auch sonst hat das Array-Verfahren in JavaFX nur auf den ersten Blick große Ähnlichkeit mit dem Vorgehen bei Datenfeldern oder Arrays in Java. Es werden erfahrenen Programmierern aus Java als auch anderen Sprachen einige interessante Überraschungen bevorstehen.
96 Wenn man sich daran gewöhnt hat!
130
Das Syntaxkonzept von JavaFX Script
3.7.1 Was sind Arrays? Arrays beziehungsweise Datenfelder bezeichnen allgemein eine sequenzielle Sammlung von Inhalten gleichen Typs, die alle über einen gemeinsamen Bezeichner und einen in eckigen Klammern notierten Index (in Java als auch JavaFX bei 0 beginnend) angesprochen werden können. Beispiel: zahlen [1]; Listing 3.32: Zugriff auf den zweiten Wert eines Arrays
Datenfelder sind beispielsweise immer dann von großem Nutzen, wenn eine Reihe von gleichartigen oder logisch zusammenfassbaren Informationen gespeichert werden sollen. Ein Hauptvorteil von Arrays ist, dass der Zugriff auf die einzelnen Einträge im Array über den numerischen Index erfolgen kann. Das kann man beispielsweise in Schleifen gut ausnutzen.
3.7.2 Arrays in JavaFX Trotz der unbestreitbaren Ähnlichkeit aller Array-Techniken im Allgemeinen und der Verwandtschaft von Java und JavaFX im Besonderen implementiert JavaFX Arrays teilweise sehr ungewöhnlich. Es handelt sich insbesondere bei Arrays in JavaFX nicht um die gleichen Arrays, wie sie in Java vorkommen. Zum Ersten werden in JavaFX Arrays nicht als Objekte gesehen und es stehen damit keine Eigenschaften oder Methoden zur Verfügung. In Java sind es Objekte. Ebenso sind in JavaFX keine verschachtelten Arrays möglich. Das Erzeugen von Arrays in JavaFX erfolgt über eine eigene Syntax. Die Werte eines Arrays können einfach, durch Kommata getrennt, bei einer Zuweisung in eckigen (nicht geschweiften wie in Java) Klammern notiert werden. Beispiel: var nums = [1, 2,3]; Listing 3.33: Anlegen eines Arrays
Diese Syntax kann auch auf zwei Anweisungen verteilt werden, was bei der verwandten Array-Erzeugung mit direkter Initialisierung in Java nicht geht. var nums; nums = [1, 2,3]; Listing 3.34: Anlegen eines Arrays in zwei Schritten
131
Kapitel 3
Die Unterschiede in der Array-Erzeugung mit direkter Initialisierung in Java leiten dazu über, dass auch andere Syntaxkonstrukte aus Java in JavaFX nicht funktionieren. Etwa die Java-Form zum Deklarieren einer Referenzvariable auf ein Array oder das Anlegen eines Arrays, wie es in Java verwendet wird (oder zumindest eine daran maximal angepasste Version). Also wäre so etwas wie hier falsch: var x[]; var y = {1,2,3}; var z[] = {1,2,3}; Listing 3.35: So etwas geht alles in JavaFX nicht
Allerdings können Sie in JavaFX zum Anlegen eines Arrays Folgendes machen (das ist dann weitgehend97 analog wie in Java): var y = new Integer[5]; Listing 3.36: Eine weitgehend der Java-Syntax entsprechende Form des Anlegens eines Arrays
Was Arrays in JavaFX noch massiv auszeichnet, ist, dass Sie hier auch den Variablenbezeichner ganz ohne Index verwenden können. Oder genauer – der Index lässt sich als XPath- respektive XQuery-Ausdruck verstehen. Schauen wir uns zur Verdeutlichung ein vollständiges Beispiellisting an (javafxapp2): 01 02 03 04 05 06 07 08 09
Listing 3.37: Der Zugriff auf die einzelnen Werte in der Variablen nums
In dem Beispiel wird eine Variable nums mit mehreren Werten angelegt. Die Werte werden dann in der Konsole ausgegeben. Die Ausgabe ist folgende: 1 1 2 3 Beachten Sie insbesondere Zeile 7! 97 Außer der Deklaration der Variablen mit var.
132
Das Syntaxkonzept von JavaFX Script
In JavaFX ist [] ein eigener Operator und dieser Operator [] steht für eine Selektion. Die darin notierte Lokalisierung ist eine Verwendung, die wie gesagt ähnlich in XPath beziehungsweise XQuery vorkommt.
> >
>
HINWEIS
Unter XML Path Language oder kurz XPath versteht man eine vom W3C entwickelte Lokalisierungssprache, um Bestandteile in einem XML-Dokument ansprechen zu können. Ein XPath-Ausdruck versteht ein XML-Dokument als Baum. Dieser ist aus so genannten Knoten (nodes) und Achsen (axis) aufgebaut. Als Knoten des Baumes werden alle Bestandteile des XML-Dokuments (Elemente, Attribute, Kommentare, etc.) gesehen, die in einer Hierarchie einsortiert werden. Achsen in dem Baum werden in XPath wie der Stamm beziehungsweise die Äste des Baums verstanden und berücksichtigen auch die Reihenfolge der Elementdeklarationen (aus sequentieller Sicht). Wie in einem Verzeichnispfad können Sie unter XPath einen Knoten oder eine Achse ansprechen. Bei der Angabe wird immer der aktuelle Knoten in der Baumstruktur des XML-Dokuments als Basis verwendet. Dies ist vollkommen analog der Art und Weise, wie Sie Pfadangaben in einem Verzeichnisdienst machen. Auch dort stehen Sie in einem aktuellen Verzeichnis und geben von da den Weg zu einem anderen Ort (einem anderen Verzeichnis oder einer Datei) an. Unter XPath verwenden Sie zur Lokalisierung einen oder mehrere Lokalisierungsschritte (Location Steps), die gegebenenfalls wie unter Unix mit dem Token / getrennt werden. Wollen Sie die Wurzel des XML-Dokuments ansprechen, wird ein XPath-Ausdruck (wie unter Unix) direkt mit dem Token / begonnen. Ein Lokalisierungsschritt besteht immer aus der Angabe einer Achse und einem so genannten Knotentest (node-test), dem optional Prädikate (predicates) folgen können. Dabei lassen sich beliebig viele XPath-Ausdrücke mit dem Oder-Operator | verbinden und Achsen können gelegentlich mit zusammengesetzten Bezeichnern angesprochen werden, wenn dies einen XPath-Ausdruck verkürzt. Ebenso gibt es für Pfadangaben auf Achsen einige Abkürzungen, die der Notation in Verzeichnisangaben sehr ähnlich sind. In Bezug auf einige Anwendungen in JavaFX ist nun vor allem eine auf XPath aufsetzende Sprache mit Namen XQuery (XML Query) von Bedeutung. Dies ist eine standardisierte Abfragesprache für XML-Datenbanken, die vom World Wide Web Consortium entwickelt wurde und dort eine ähnliche Funktion ausüben soll wie SQL (ursprünglich die Abkürzung für Structured Query Language – seit einigen Jahres steht es für Standard Query Language) für relationale Datenbanken. XQuery ist auch nicht auf XML-Daten beschränkt, sondern kann für verschiedene Abfragen eingesetzt werden – eben auch im Zusammenhang mit JavaFX, was wir unter anderem in diesem Abschnitt sehen werden.
Aus dieser Xpath angelehnten Sicht ist der Ausdruck in den eckigen Klammern [] ein Boolescher Ausdruck98. Und dieser gibt ein neues Array zurück, das nur die Elemente enthält, die durch diesen Ausdruck in den eckigen Klammern beschrieben werden.
98 Diese Sichtweise unterscheidet sich gänzlich von der in Java.
133
Kapitel 3
Sie formulieren also in den eckigen Klammern einen Lokalisierungsausdruck und erhalten damit eine Teilmenge des Originaldatenfeldes.
> >
>
HINWEIS
JavaFX tritt mit dem Anspruch an, die Programmierung von Java-Applikation zu erleichtern. Jedoch habe ich in meinen XML-Kursen die Erfahrungen gemacht, dass sowohl XPath als auch XQuery ganz und gar nicht so einfach und verständlich sind, wie es immer propagiert wird. Im Gegenteil – für Einsteiger ist der Umgang mit solchen Lokalisierungsschritten nach meiner Erfahrung sogar extrem schwierig. Die Motivation für die Einführung in JavaFX dürfte aber sein, dass es mittlerweile dennoch ein recht verbreitetes Wissen im XML-Umfeld gibt (auch bei Leuten, die nicht programmieren) und man diese Syntax alternativ zu einer klassischen Programmierung für den Zugriff auf Teile eines Arrays verwenden kann – immerhin soll sich JavaFX auch Nichtprogrammierern verständlich zeigen. Oder um es so zu formulieren – wenn Ihnen diese Syntax gefällt und Sie damit klarkommen, ist es wunderbar. Dann sollten Sie diese einsetzen. Wenn Sie sie aber nicht verstehen, können Sie sämtliche Lokalisierungen auf einem vollständigen Array auch mit der klassischen Programmierung über Bedingungen und Schleifen durchführen. Sie können diese Lokalisierung also als ein Angebot von JavaFX verstehen, das Sie auch ausschlagen können, um stattdessen mit klassischen Programmiertechniken zu arbeiten.
3.7.3 Abfragen auf Arrays JavaFX stellt eine größere Anzahl an Lokalisierungsausdrücken zur Verfügung. Sie können zum Beispiel Vergleiche auf den Index formulieren. Dabei deklarieren Sie in der Regel auf eine etwas ungewohnte Weise (mit einem |-Operator) eine Variable für das aktuelle Kontextobjekt, auf dem Sie eine Abfrage zur Ermittlung eines Teildatenfeldes formulieren. Beispiel: var nums = [1,2,3,4]; var numsGreaterThanTwo = nums[n|n > 2]; // liefert [3, 4] Listing 3.38: Auswahl eines Teildatenfeldes
> >
>
HINWEIS
Wie auch in XPath kann man nach den offiziellen Dokumentationen in JavaFX bei einem Testausdruck mit dem Punktoperator auf das Kontextobjekt zugreifen. Schauen wir uns eine entsprechende Variante unseres Beispiels an: var nums = [1,2,3,4]; var numsGreaterThanTwo = nums[. > 2]; // liefert [3, 4] Listing 3.39: Eine Alternative zur Auswahl eines Teildatenfeldes
134
Das Syntaxkonzept von JavaFX Script
Interessanterweise macht diese Syntax, die auch in vielen offiziellen Beispielen zu JavaFX Verwendung findet, beim Übersetzen Probleme. Bei diversen Konstellationen kommt bei der Verwendung des Punktoperators eine Fehlermeldung der folgenden Art: Error in file: ... incompatible types: expected Number, found Boolean in ... Die zuerst genannte Schreibweise funktioniert aber meist einwandfrei, wenn man sie alternativ einsetzen kann. Hier zeigt sich wahrscheinlich auch, dass zum Zeitpunkt der Bucherstellung JavaFX noch in einer Betaversion vorliegt.
In JavaFX gibt es den Operator indexof. Dieser gibt die ordinale Position von einem Element innerhalb eines Arrays zurück99. In JavaFX wird das leere Array mit [] bezeichnet. Dies ist ein identischer Ausdruck zu dem Token null. Deshalb liefert ein Vergleich auch true.
3.7.4 Die Größe eines Arrays – sizeof Die Größe von einem Array100 kann man in Java ganz einfach bestimmen, da jedes Array ein Objekt ist. Dies ist wie gesagt in JavaFX nicht so. Zur Bestimmung der Größe von einem Array in JavaFX muss man einen Operator verwenden – den sizeof-Operator. Beispiel: var n = sizeof num; Listing 3.40: die Größe von einem Array
Schauen wir uns ein vollständiges Beispiel mit einem leeren Array und sizeof an (leeresarray): 01 02 03 04 05
Die Ausgabe ist Folgende: true 0 0 99 Das entspricht exakt der Funktion position() in XPath. 100 Also die Anzahl der enthaltenen Elemente.
135
Kapitel 3
3.7.5 Eine Kurznotation für Arrays mit einer arithmetischen Serie Es gibt in JavaFX eine Kurznotation für Arrays mit einer arithmetischen Serie (eine lineare Folge an Zahlen). Man notiert in die eckigen Klammern einfach zwei Punkte (..) zwischen den Start- und Endwert für die Zahlenfolge. Wenn Sie am Beginn des Wertebereichs zwei Zahlen angeben, die Sie mit einem Komma trennen, geben Sie eine Schrittweite der Werte an, mit der das Datenfeld gefüllt wird. Indirekt legen Sie damit natürlich dann auch die Anzahl der Werte in dem Datenfeld und damit die Größe von dem Datenfeld fest. Hier sehen Sie zum Beispiel die Definition einer Funktion, die als Rückgabewert alle Zahlen in einem Datenfeld addiert, sowie eine zweite Funktion, die nur die geraden Zahlen addiert (arrayarithmetischeserie): 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
import java.lang.System; // Addition aller Zahlen von 1 bis zum Wert des Übergabewertes operation addZahlen(n) { var x = 0; for(i in [1..n]) { x +=i; } return x; } // Addition aller geraden Zahlen von 2 bis zum Wert des Übergabewertes operation addGeradeZahlen(n) { var x = 0; for(i in [2,4..n]) { x +=i; } return x; } // Summe von 1 bis 5 System.out.println(addZahlen(5)); // Summe aller geraden Zahlen von 2 bis 10 System.out.println(addGeradeZahlen(10)); // Größe des Array von 1 bis 100 mit allen Zahlen System.out.println(sizeof [1..100]); // Größe des Array von 1 bis 100 mit allen Zahlen und der Schrittweite 4 System.out.println(sizeof [1,5..100]);
Listing 3.42: Datenfeldern mit Zahlenfolgen
136
Das Syntaxkonzept von JavaFX Script
Die Ausgabe ist Folgende: 15 30 100 25
3.7.6 Die Modifikation von Arrays – Elemente einfügen Allgemein werden Werte von Arrays über die Zuweisung eines neuen Werts modifiziert. Arrays sind nun aber in Java bei weitem nicht so flexibel zu handhaben, wie man es möglicherweise annimmt. Java verwendet so genannte semidynamische Datenfelder, da die Größe eines Datenfelds zwar nicht bei der Deklaration festgelegt werden muss, sondern sich auch erst zur Laufzeit ergeben kann. Das ist der dynamische Anteil. Das vorangestellte semi bedeutet, dass in Java ein Datenfeld jedoch nicht mehr in der Größe verändert werden kann, wenn es einmal in der Größe festgelegt wurde. Sie können also keine weiteren Elemente hinzufügen, noch können Sie vorhandene Elemente löschen101. Sollten Sie beispielsweise ein Datenfeld mit 100 Einträgen erzeugt haben und Sie benötigen 120 Elemente, dann müssen Sie ein neues Datenfeld erzeugen und die Werte der Elemente aus dem alten Datenfeld hineinkopieren. Das ist absolut nicht schwierig, aber recht unbequem. Aus diesem Grund hat man sukzessive in Java Erweiterungen von normalen Datenfeldern eingeführt, die eine vollständige dynamische Veränderung gestatten. JavaFX verwendet nun Mechanismen, die einen dynamischen Umgang mit Datenfeldern gestatten102. Zusätzlich zu dem Zuweisungsoperator (=) zum Verändern eines Werts von einem Element gibt es in JavaFX Operatoren zur dynamischen Modifikation der Anzahl von Elementen in Arrays (data modification operators). Dies sind insert und delete. Sie werden identisch in der Syntax als auch Semantic eingesetzt wie diejenigen, die in der zukünftigen Version von XQuery Verwendung finden sollen.
101 Natürlich können Sie einen Wert auf null oder sonst einen leeren Wert setzen. 102 Wie das genau im Hintergrund mit Java gehandhabt wird, ist dabei vollkommen egal.
137
Kapitel 3
Einfügen von Elementen – die insert-Anweisung Mit der insert-Anweisung fügen Sie Elemente zu einem bestimmten Datenfeld hinzu. Diese Anweisung kann verschiedene Formen annehmen: insert Ausdruck1 [as first | as last] into Ausdruck2 insert Ausdruck1 before Ausdruck2 insert Ausdruck1 after Ausdruck2 Listing 3.43: Schemata für die unterschiedliche Verwendung von insert
Die Anweisung insert fügt die Elemente, die sich durch die Evaluierung von Ausdruck1 ergeben, an einer bestimmten Stelle in das Datenfeld ein. Dabei muss Ausdruck2 hinter dem Schlüsselwort into auf ein Attribut eines Objekts oder eine Variable verweisen.
> >
>
HINWEIS
Wenn Ausdruck2 auf ein Attribut mit nur einem Wert verweist, hat der Operator insert den gleichen Effekt wie der Zuweisungsoperator.
Wenn der Token as first angegeben wird, erfolgt die Einfügung des neuen Elements beziehungsweise der Elemente vor dem ersten Element der Liste, die mit Ausdruck2 spezifiziert wird. Wenn stattdessen der Token as last angegeben wird, erfolgt vollkommen analog das Einfügen hinter dem letzten Element der mit Ausdruck2 spezifizierten Liste. Wenn weder as first noch as last explizit angegeben werden, gilt als Vorgabe as last. Beispiel (arrayinsert): 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16
138
import java.lang.System; // Operation zur Ausgabe wichtiger Eckdaten des Arrays operation auswertungArray(x){ // Größe des Arrays System.out.println("Groesse des Arrays: {sizeof x}"); // interner Zähler für die folgende Schleife var counter = 0; // Ausgabe aller Elemente in dem Array for(i in x) { System.out.println("Wert von Index {counter++}: {i}"); } // Trennlinie System.out.println("__________________________"); }
// Anlegen eines Arrays var x = [1,2,3]; auswertungArray(x); // Einfügen eines Wertes - Defaulteinstellung insert 12 into x; System.out.println("Anweisung: insert 12 into x "); auswertungArray(x); // Einfügen eines Wertes am Anfang insert 10 as first into x; System.out.println( "Anweisung: insert 10 as first into x"); auswertungArray(x); // Einfügen zweier Werte (Array) am Ende insert [99,100] as last into x; System.out.println( "Anweisung: insert [99,100] as last into x"); auswertungArray(x); // Einfügen einer arithmetischen Serie am Anfang insert [40,44 .. 55] as first into x; System.out.println( "Anweisung: insert [40,44 .. 55] as first into x"); auswertungArray(x);
Listing 3.44: Einfügen von Elementen
In dem Beispiel finden Sie von der Zeile 4 bis zu Zeile 15 eine Operation (auswertungArray()), die die wichtigsten Eckdaten des Arrays ausgibt. Wir rufen diese Operation nach jeder Veränderung des Arrays auf um zu kontrollieren, wie sich die Größe des Arrays geändert hat und welche Elemente nun darin enthalten sind. Die Operation bekommt als Übergabewert eine Referenz auf das Array übergeben. Die Variable x wird in Zeile 18 deklariert und mit einem Defaultwert (ein Array mit drei Einträgen) belegt. In Zeile 22 sehen Sie das Einfügen eines Wertes mit der Defaulteinstellung. Damit wird das neue Element am Ende des bestehenden Arrays eingefügt (insert 12 into x;). In Zeile 27 sehen Sie dagegen das Einfügen eines Wertes am Anfang des bestehenden Arrays mit der Anweisung insert 10 as first into x;. Die Zeile 33 zeigt das Einfügen zweier Werte (also eines Arrays), die explizit an das Ende des bestehenden Arrays angefügt werden (insert [99,100] as last into x;). Die Aktion in Zeile 39 zeigt Ihnen das Einfügen einer arithmetischen Serie am Anfang eines bestehenden Arrays (insert [40,44 .. 55] as first into x;).
139
Kapitel 3
Das ist die Ausgabe des Beispiels: Groesse des Arrays: 3 Wert von Index 0: 1 Wert von Index 1: 2 Wert von Index 2: 3 __________________________ Anweisung: insert 12 into x Groesse des Arrays: 4 Wert von Index 0: 1 Wert von Index 1: 2 Wert von Index 2: 3 Wert von Index 3: 12 __________________________ Anweisung: insert 10 as first into x Groesse des Arrays: 5 Wert von Index 0: 10 Wert von Index 1: 1 Wert von Index 2: 2 Wert von Index 3: 3 Wert von Index 4: 12 __________________________ Anweisung: insert [99,100] as last into x Groesse des Arrays: 7 Wert von Index 0: 10 Wert von Index 1: 1 Wert von Index 2: 2 Wert von Index 3: 3 Wert von Index 4: 12 Wert von Index 5: 99 Wert von Index 6: 100 __________________________
140
Das Syntaxkonzept von JavaFX Script
Anweisung: insert [40,44 .. 55] as first into x Groesse des Arrays: 11 Wert von Index 0: 40 Wert von Index 1: 44 Wert von Index 2: 48 Wert von Index 3: 52 Wert von Index 4: 10 Wert von Index 5: 1 Wert von Index 6: 2 Wert von Index 7: 3 Wert von Index 8: 12 Wert von Index 9: 99 Wert von Index 10: 100 __________________________
Die Angaben before und after Wie Sie eben gesehen haben, können Sie Elemente am Ende oder am Anfang eines bestehenden Arrays einfügen. Mit JavaFX können Sie aber auch an einer beliebigen Stelle im Array neue Elemente hinzufügen. Dazu dienen die Angaben before und after. Ausdruck2 muss ein Selektionsausdruck über ein Attribut oder eine Variable sein. Wenn der Token before angegeben wird, erfolgt die Einfügung vor dem spezifizierten Element. Entsprechend erfolgt die Einfügung bei after danach. Beispiel (arrayinsertbevorafter – die Operation ist identisch zu dem vorherigen Beispiel und wird hier aus Platzgründen nicht mehr abgedruckt): 01 import java.lang.System; 02 03 // Operation zur Ausgabe wichtiger Eckdaten des Arrays 04 operation auswertungArray(x){ ... 15 } 16 17 // Anlegen eines Arrays 18 var x = [1,2,3]; 19 auswertungArray(x); 20 21 // Einfügen eines Wertes nach dem Element mit dem Wert 1
141
Kapitel 3 22 23 24 25 26 27 28 29 30 31 32 33 34
insert 10 after x[n|n == 1]; System.out.println("Anweisung: insert 10 after x[n|n == 10]"); auswertungArray(x); // Einfügen eines Wertes an der 2. Stelle des bestehenden Arrays insert 12 before x[1]; System.out.println("Anweisung: insert 12 before x[1]"); auswertungArray(x); // Einfügen eines Wertes nach dem Element mit dem Wert 2 insert 13 after x[n|n == 2]; System.out.println("Anweisung: insert 13 after x[n|n == 2]"); auswertungArray(x);
Listing 3.45: Das gezielte Einfügen an einer beliebigen Stelle im bestehenden Array
In der Zeile 22 sehen Sie das Einfügen eines Wertes nach dem Element mit dem Wert 1 (insert 10 after x[n|n == 1];). Das bedeutet, dass der Wert 10 in dem vorher vorhandenen Array zwischen den Werten 1 und 2 eingefügt wird. Er steht damit in dem neuen Array an der Position 2 (das ist der Index 1). In Zeile 27 sehen Sie das explizite Einfügen eines Wertes an einer bestimmten Stelle im bisherigen Array, die über einen Index spezifiziert wird. Das ist in diesem Fall die zweite Stelle des bestehenden Arrays (insert 12 before x[1];). In Zeile 32 erfolgt erneut das Einfügen eines Wertes nach einem Element, das über einen Wert spezifiziert wird (insert 13 after x[n|n == 2];). Die Ausgabe des Beispiels ergibt das: Groesse des Arrays: 3 Wert von Index 0: 1 Wert von Index 1: 2 Wert von Index 2: 3 __________________________ Anweisung: insert 10 after x[n|n == 10] Groesse des Arrays: 4 Wert von Index 0: 1 Wert von Index 1: 10 Wert von Index 2: 2 Wert von Index 3: 3 __________________________
142
Das Syntaxkonzept von JavaFX Script
Anweisung: insert 12 before x[1] Groesse des Arrays: 5 Wert von Index 0: 1 Wert von Index 1: 12 Wert von Index 2: 10 Wert von Index 3: 2 Wert von Index 4: 3 __________________________ Anweisung: insert 13 after x[n|n == 2] Groesse des Arrays: 6 Wert von Index 0: 1 Wert von Index 1: 12 Wert von Index 2: 10 Wert von Index 3: 2 Wert von Index 4: 13 Wert von Index 5: 3 __________________________
3.7.7 Das Löschen von Elementen in einem Array – die delete-Anweisung Die Anweisung delete löscht Elemente aus einem vorhandenen Datenfeld. Dabei kann diese Anweisung folgende Formen annehmen: delete delete delete delete
Listing 3.46: Schemata für alternative Formen für die delete-Anweisung
Die ersten zwei Varianten entfernen alle Elemente aus einer Variablen oder einem Attribut. Dies ist äquivalent zu der Zuweisung von [] oder null zu der Variablen oder dem Attribut. Die letzten beiden Varianten entfernen nur die Elemente, die mit dem Prädikat (einem Testausdruck) übereinstimmen.
143
Kapitel 3
Beispiel (arraydelete – die Operation ist identisch zu dem vorherigen Beispiel und wird nicht mehr abgedruckt): 01 import java.lang.System; 02 03 // Operation zur Ausgabe wichtiger Eckdaten des Arrays 04 operation auswertungArray(x){ ... 15 } 16 17 // Anlegen eines Arrays 18 var x = [1, 2, 3, 4, 5, 6, 7, 8 , 1, 3, 5, 7, 9, 11]; 19 auswertungArray(x); 20 21 // Löschen des Eintrags mit dem Wert 6 22 System.out.println("Anweisung: delete x[n|n == 6]"); 23 delete x[n|n == 6]; 24 auswertungArray(x); 25 26 // Löschen aller Einträge mit dem Wert >= 3 27 delete x[n|n >= 3]; 28 System.out.println("Anweisung: delete x[n|n >= 3]"); 29 auswertungArray(x); 30 31 // Löschen aller Einträge 32 System.out.println("Anweisung: delete x"); 33 delete x; 34 auswertungArray(x); Listing 3.47: Löschen von Array-Elementen
In dem Beispiel arbeiten wir dieses Mal mit einem etwas größeren Array. Wir wollen ja einige Elemente löschen. Es sollte Ihnen auch auffallen, dass sich einige Werte in dem Array wiederholen. In Zeile 23 erfolgt das gezielte Löschen des Eintrags mit dem Wert 6 (delete x[n|n == 6];). In Zeile 27 löschen wir alle Einträge mit dem Wert >= 3 (delete x[n|n >= 3];). Da der Wert 1 im Original-Array zwei Mal vorkommt, bleibt ein Array mit drei Einträgen übrig. Die Zeile 33 löscht alle Einträge in dem verbleibenden Array (delete x;). Das ist die Ausgabe des Beispiels: Groesse des Arrays: 14 Wert von Index 0: 1 Wert von Index 1: 2 Wert von Index 2: 3
144
Das Syntaxkonzept von JavaFX Script
Wert von Index 3: 4 Wert von Index 4: 5 Wert von Index 5: 6 Wert von Index 6: 7 Wert von Index 7: 8 Wert von Index 8: 1 Wert von Index 9: 3 Wert von Index 10: 5 Wert von Index 11: 7 Wert von Index 12: 9 Wert von Index 13: 11 __________________________ Anweisung: delete x[n|n == 6] Groesse des Arrays: 13 Wert von Index 0: 1 Wert von Index 1: 2 Wert von Index 2: 3 Wert von Index 3: 4 Wert von Index 4: 5 Wert von Index 5: 7 Wert von Index 6: 8 Wert von Index 7: 1 Wert von Index 8: 3 Wert von Index 9: 5 Wert von Index 10: 7 Wert von Index 11: 9 Wert von Index 12: 11 __________________________
145
Kapitel 3
Anweisung: delete x[n|n >= 3] Groesse des Arrays: 3 Wert von Index 0: 1 Wert von Index 1: 2 Wert von Index 2: 1 __________________________ Anweisung: delete x Groesse des Arrays: 0 __________________________
3.7.8 Auswählen von Elementen – die select- und die foreach-Anweisung JavaFX unterstützt über die Anweisung select sowie die schon an anderer Stelle behandelte Anweisung foreach die Auswahl von Elementen. Das Ergebnis wird eine Liste mit Treffern sein, die eine Teilmenge des bisherigen Arrays darstellen. Dabei kann man optional mit der Erweitung where einen Filter (einen Testausdruck) spezifizieren. Die beiden Anweisungen entsprechen in hohem Maß der select-Anweisung in SQL. Hier ist ein Schema für die Verwendung: select Ausdruck from Array [where Bedingung] Listing 3.48: Ein Schema für die Anwendung der select-Anweisung
Schauen wir uns ein Beispiel an (selectanweisung): 01 02 03 04 05 06 07 08 09 10 11 12 13
import java.lang.System; // Die Quadrate der Zahlen 1 bis 10 var zahlen = select n*n from n in [1..10]; for(i in zahlen) { System.out.println(i); } // Alle geraden Zahlen zwischen 1 und 30 (inklusive) zahlen = select j from j in [1..30] where j % 2 == 0; for(i in zahlen) { System.out.println(i); }
Listing 3.49: Die Anwendung von select
146
Das Syntaxkonzept von JavaFX Script
Die Anweisung in Zeile 4 gibt die Quadrate der Zahlen 1 bis 10 als Ergebnis. Dabei ist n als eine lokale Variable des Ausdrucks zu sehen. Die Anweisung in Zeile 9 liefert alle geraden Zahlen zwischen 1 und 30 (inklusive). Dabei kommt ein Filter zum Einsatz, der mittels des Schlüsselworts where eingeleitet wird. Hier ist noch ein umfangreicheres Beispiel mit dem Einsatz von select und foreach (selectanweisung1): 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
import java.lang.System; class Album { attribute title: String; attribute artist: String; attribute tracks: String*; } var albums = [Album { title: "A Hard Day's Night" artist: "The Beatles" tracks: ["A Hard Day's Night", "I Should Have Known Better", "If I Fell", "I'm Happy Just To Dance With You", "And I Love Her", "Tell Me Why", "Can't Buy Me Love", "Any Time At All", "I'll Cry Instead", "Things We Said Today", "When I Get Home", "You Can't Do That"] }, Album { title: "Circle Of Love" artist: "Steve Miller Band" tracks: ["Heart Like A Wheel", "Get On Home", "Baby Wanna Dance", "Circle Of Love", "Macho City"] }]; var counter = 0; // Abfrage aller Titelnummern, die mit dem Titel des jeweiligen // Albums übereinstimmen
147
Kapitel 3 40 41 42 43 44 45 46 47 48 49
// Anwendung des select-Operators: System.out.println("Anwendung des select-Operators:"); var titleTracks = select indexof track + 1 from album in albums, track in album.tracks where track == album.title; for(i in titleTracks) { System.out.println( "Im {++counter}. Album stimmt der Titel {i} mit dem Namen des Albums ueberein."); 50 } 51 52 // Alternative über den Operator foreach 53 counter = 0; 54 System.out.println("Anwendung des foreach-Operators:"); 55 titleTracks = 56 foreach (album in albums, 57 track in album.tracks 58 where track == album.title) 59 indexof track + 1; 60 for(i in titleTracks) { 61 System.out.println( 62 "Im {++counter}. Album stimmt der Titel {i} mit dem Namen des Albums ueberein."); 63 }
Listing 3.50: Die Anwendung von select und foreach
Das Beispiel arbeitet mit der deklarativen Erzeugung von Objekten, die wir im nächsten Kapitel genauer besprechen werden. Bis zur Zeile 35 sollten Sie den Quellcode deshalb erst einmal so hinnehmen. Die beiden erzeugten Objekte repräsentieren Musikalben mit einer gewissen Anzahl an enthaltenen Stücken. In Zeile 37 definieren wir eine Zählvariable (var counter = 0;), die einfach die nachfolgenden Ausgaben etwas verständlicher aufbereiten soll. In der Zeile 43 bis 46 sehen Sie eine komplexere select-Anweisung (var titleTracks = select indexof track + 1 from album in albums, track in album.tracks where track == album.title;). Diese dient zur Abfrage aller Titelnummern, die mit dem Titel des jeweiligen Albums übereinstimmen. Das Ergebnis der Abfrage sind die jeweiligen Titelnummern. In der folgenden Schleife wird das Ergebnis optisch etwas aussagekräftiger aufbereitet. In den Zeilen 56 bis 59 sehen Sie eine vollkommen äquivalente Abfrage. Sie wird nur über den Operator foreach ausgeführt.
148
Das Syntaxkonzept von JavaFX Script
Das ist die Ausgabe des Beispiels: Anwendung des select-Operators: Im 1. Album stimmt der Titel 1 mit dem Namen des Albums ueberein. Im 2. Album stimmt der Titel 4 mit dem Namen des Albums ueberein. Anwendung des foreach-Operators: Im 1. Album stimmt der Titel 1 mit dem Namen des Albums ueberein. Im 2. Album stimmt der Titel 4 mit dem Namen des Albums ueberein.
3.8 Bezeichner in französischen Anführungszeichen In JavaFX wird jede Sequenz an Zeichen, die in so genannten französischen Anführungszeichen notiert sind (<<>>), als Bezeichner verstanden. Dies erlaubt es zum Beispiel JavaFX-Schlüsselwörter als Bezeichner für Klassen, Variablen, Funktionen oder Attribute zu verwenden. Das bedeutet, so etwas wäre theoretisch möglich: var <<while>> = 100; Listing 3.51: Ein Bezeichner für eine Variable, der mit einem Schlüsselwort übereinstimmt
Nun gehört es zu den elementarsten Regeln guten Programmierstils, keine Bezeichner zu verwenden, die auch nur ansatzweise Schlüsselwörtern ähneln103. Solch eine missverständliche Verwendung erschwert die Wartbarkeit gewaltig. Aber es gibt dennoch tatsächlich eine sinnvolle Anwendung für diese Möglichkeit. Sie können damit Java-Methoden in JavaFX aufrufen, deren Namen wie Schlüsselwörter in JavaFX lauten. Und solche Fälle gibt es in der Tat. Hier wäre ein Beispiel: import javax.swing.JTextArea; var textArea = new JTextArea(); textArea.<>("Hello", 0); Listing 3.52: Aufruf einer Java-Methode, die einem JavaFX-Schlüsselwort entspricht
103 So etwas kann man auf Grund der Relevanz von Groß- und Kleinschreibung in verschiedenen Sprachen machen, indem man zum Beispiel eine Variable IF nennt, wenn das Schlüsselwort if ist.
149
4
OOP in JavaFX Script
Im letzten Kapitel haben wir uns mit der Syntax von JavaFX Script auseinander gesetzt. Sie haben dabei meist sequenziell abgearbeitete Anweisungen als Beispiele gesehen. Diese haben zwar Klassen und Objekte verwendet und sogar auch explizit Objekte erzeugt, aber eher nebenher. In diesem Kapitel gehen wir nun genauer auf das Konzept der objektorientierten Programmierung (kurz OOP) ein. Natürlich speziell in Hinsicht auf JavaFX Script. Dabei werden wir zuerst jedoch die wichtigsten Grundlagen von der OOP inklusive einiger zugehöriger Begriffe erklären, um dann die Verwendung von Objekten in JavaFX sowie das Erzeugen eigener Objekte zu besprechen.
4.1 Was ist OOP und was sind Objekte? Applikationen können in JavaFX unmittelbar JavaKlassen aus beliebigen Paketen des Java-Standard-APIs importieren, neue Java-Objekte erstellen, deren Methoden aufrufen und Eigenschaften nutzen, sowie Java-Schnittstellen implementieren und eigene Objekte erzeugen. In diesem Satz steckt nun bereits eine Menge an Begriffen zu Java und objektorientierter Programmierung drin. Und die Grundlagen der objektorientierten Programmierung müssen Sie zumindest in Grundzügen kennen, um das zentrale Verfahren der Erstellung von JavaFX-Applikationen überhaupt zu verstehen. Gehen wir die OOP-Grundlagen also systematisch an, soweit Sie diese für JavaFX wissen sollten.
Kapitel 4
4.1.1 Objekte und Klassen In der objektorientierten Programmierung (OOP) spricht man in erster Linie immer wieder von Objekten und Klassen als zentrale Begriffe. Auch in dem Buch wurden die Begriffe schon häufig verwenden. Und was sich aber genau dahinter verbirgt, klären wir jetzt. TIPP
Auch wenn man mit JavaFX nicht streng objektorientiert arbeitet und Sun sich mit JavaFX Script explizit die Erleichterung der Erstellung von Applikationen ohne zu viel Background-Wissen zu OOP als auch Java auf die Fahnen geschrieben hat – wer sich bisher nicht mit OOP auskennt, sollte sich unbedingt den folgenden Abschnitt zu Gemüte führen, um zumindest grob das Konzept zu verstehen.
Eigenschaften Wenn Sie in der realen Welt ein Handy in die Hand nehmen, können Sie die Eigenschaften dieses (realen) Objekts beschreiben – beispielsweise seine Form, die Größe oder die Farbe. Sie können alle Eigenschaften (oft auch Attribute genannt) des Objekts aufführen, soweit es für Sie notwendig bzw. sinnvoll ist.
Methoden Und Sie können die Dinge beschreiben, die Sie aktiv mit dem Handy machen können (das nennt man in der OOP dann Methoden). Zum Beispiel telefonieren104.
Zustand Dabei ist es offensichtlich, dass Sie nur dann telefonieren können, wenn das Handy zu diesem Zeitpunkt eingeschaltet ist und Empfang hat. Offensichtlich kann sich ein reales Objekt in einem spezifischen Zustand befinden und bestimmte Dinge in Abhängigkeit davon bereitstellen oder auch nicht, wenn sie grundsätzlich vorhanden sind.
> >
>
HINWEIS
Genau diese drei Schlagworte – Eigenschaften, Methoden und Zustand – prägen das gesamte Verständnis von Objekten. Die objektorientierte Denkweise im Computerumfeld entspricht damit vollkommen dem Abbild der realen Natur und den Objekten, die wir dort wahrnehmen. Die Objektorientierung im Rahmen der EDV versucht einfach, diese aus der realen Welt so natürlichen Vorstellungen in die EDV zu übertragen.
104 Das soll angeblich bei modernen Handys noch möglich sein – ich habe dieses Feature allerdings bei der Vielzahl an Spielereien auf meinem Handy bisher noch nicht gefunden ;-).
152
OOP in JavaFX Script
Die OOP als Abstraktion In der OOP stellt man sich unter einem Objekt allgemein ein abstraktes Softwaremodell vor, das ein Ding aus der realen Welt mit all seinen relevanten Eigenschaften und (von einem Zustand abhängigen) Verhaltensweisen repräsentieren soll und das einem Anwender über ein Symbol oder einen Bezeichner zugänglich ist. Zum Beispiel kann das eine Repräsentation eines Teils der Hardware, aber auch ein Frame in einem Programm sein. Im Grunde ist im objektorientierten Denkansatz alles als Objekt zu verstehen, was sich eigenständig erfassen und ansprechen lässt. Die gesamte objektorientierte Philosophie entspricht viel mehr der realen Natur als der klassische prozedurale Denkansatz der althergebrachten Programmierung, der von der Struktur des Computers definiert wird. Ein Objekt ist im Sinne der objektorientierten Philosophie eine Abstraktion eines in sich geschlossenen Elements der realen Welt. Dabei spricht man von Abstraktion, weil zur Lösung eines Problems normalerweise weder sämtliche Aspekte eines realen Elements benötigt werden noch überhaupt darstellbar sind. Irgendwo muss immer abstrahiert werden. Ein Mensch bedient sich eines Objekts, um eine Aufgabe zu erledigen. Man weiß in der Regel sogar nicht genau, wie das Objekt im Inneren funktioniert105, aber man kann es bedienen (kennt also die Methoden, um es zu verwenden) und kennt die Eigenschaften des Objekts (seine Attribute) und weiß, wann was zur Verfügung steht (sein Zustand).
Der Identifikator Der Zugriff auf ein Objekt bzw. eine Klasse erfolgt in einem Quelltext über einen Namen oder zumindest einen Stellvertreterbegriff106, der ein Objekt repräsentiert (der Identifikator). In der Regel ist der Identifikator eine Referenz (ein Zeiger bzw. Pointer) auf das tatsächliche Objekt im Hauptspeicher.
4.1.2 Botschaften Besonders wichtig ist in Zusammenhang mit der Verwendung von Objekten der Begriff der Botschaften. Damit Objekte im Rahmen eines Quelltextes verwendet werden können, sendet man Ihnen eine Botschaft107. Das Objekt, von dem ein anderes
105 Oder wissen Sie genau, wie Ihr Auto funktioniert? Ich kann bei meinem nicht einmal mehr eine Glühbirne wechseln ;-). 106 In Java bzw. JavaFX ist das für ein Objekt das Schlüsselwort this, das uns schon im letzten Kapitel begegnet ist und noch genauer erklärt wird. 107 In der Literatur findet man oft auch Nachricht bzw. englisch Message.
153
Kapitel 4
Objekt etwas will, erhält darüber eine Bitte108, eine bestimmte Methode auszuführen oder den Wert einer Eigenschaft zurückzugeben oder zu setzen. Das Zielobjekt versteht (hoffentlich) diese Aufforderung und reagiert entsprechend.
Die Punktnotation Die genaue formale Schreibweise solcher Botschaften folgt in den meisten OO-Programmiersprachen der Punktnotation bzw. DOT-Notation. Diese Notation nennt sich so, weil ein Attribut oder eine Methode eines Objekts dem Bezeichner für ein Objekt nachgestellt und über einen Punkt abgetrennt wird. Eine Botschaft, dass ein Objekt eine bestimmte Methode ausführen soll, sieht also meist wie folgt aus: Empfänger.methodenName(Argumente) Listing 4.1: Aufruf einer Methode
Die Argumente stellen in dem Botschaftsausdruck einen oder mehrere Übergabeparameter für die Methode dar. Eine ähnliche Form wird auch für die Verwendung von Objektattributen gewählt. In der Regel sieht das dann so aus: Empfänger.attributName Listing 4.2: Zugriff auf ein Attribut
4.1.3 Klassen und Konstruktor Um nun in einer Programmier- oder Skriptsprache ein Objekt erzeugen zu können, benötigt man eine Bauvorschrift in Form einer Klasse.
Der Konstruktor Um aus einer Klasse dann in einer Programmier- oder Skriptsprache ein Objekt tatsächlich zu erzeugen, verwendet man in der Regel einen so genannten Konstruktor oder englisch constructor. Dieser Konstruktor, der als (besondere) Methode zur Verfügung steht, hat in Java bzw. JavaFX immer den gleichen Namen wie die zugehörige
108 Von einer Bitte zu sprechen ist äußerst sinnvoll. Eine Botschaft ist kein Befehl im klassischen Sinn. Denken Sie etwa an eine Bitte, Werte in einen Datensatz einer Datenbank zu schreiben. Wenn zu dem Zeitpunkt ein anderer Anwender diesen Datensatz im Zugriff hat, darf man zu diesem Zeitpunkt den Datensatz nicht verändern. Die Bitte wird also abgeschlagen. Zu einem späteren Zeitpunkt wird das Objekt aber der Bitte entsprechen können. Das Schlagwort in diesem Zusammenhang ist Zustand.
154
OOP in JavaFX Script
Klasse, in der er definiert ist. Nur folgt dem Bezeichner des Konstruktors immer ein Klammernpaar109, das bei Bedarf auch Parameter enthalten kann.
> >
>
HINWEIS
Bei JavaFX muss man bezüglich des Konstruktors etwas aufpassen. Einerseits besitzen JavaFXKlassen keine Konstruktoren in dem Sinn, wie sie in Java vorkommen, sondern arbeiten mit so genannten Triggern (siehe Seite 184), wenn man beim Anlegen eines Objekts eine bestimmte Aktion durchführen möchte. Und zudem verwendet man in der Regel eine deklarative Erzeugung von Objekten mit Objektliteralen (siehe Seite 171). Andererseits kann man in JavaFX aber Konstruktoren aus Java sowie dem JavaFX-API verwenden.
Bei der Anwendung eines Konstruktors wird in Java als auch JavaFX Script immer das Schlüsselwort new (ein Operator) vorangestellt. Beispiel: Frame a = new Frame(); Listing 4.3: Einsatz eines Konstruktors – hier wird mit Java-Syntax ein Fenster erzeugt
> >
>
HINWEIS
Sehr oft werden die Begriffe Objekt und Instanz synonym verwendet. Allerdings beschreiben die Begriffe zwar das gleiche Objekt, aber unterschiedliche Sichtweisen darauf. Eine Instanz steht für die Sichtweise auf die Herkunft (über welche Klasse es also erzeugt wurde), während Objekt eine davon unabhängige Sichtweise darstellt. So oder so bleibt es aber das gleiche Objekt, und da in vielen Quellen beide Ausdrücke synonym verwendet werden, wollen wir sie auch nicht streng unterscheiden.
Der Destruktor und der Garbage Collector Das Gegenstück zu Konstruktoren nennt man allgemein Destruktoren. Solche Destruktoren beseitigen ein nicht mehr benötigtes Objekt, führen Aufräumarbeiten aus und geben Speicher frei, der von einem Objekt belegt wurde. Ohne den Einsatz von Dekstruktoren würde ein Programm im schlimmsten Fall irgendwann den gesamten Hauptspeicher des Rechners belegen. In jedem Fall würde ein Programm unnötig Hauptspeicher blockieren. In Java beziehungsweise JavaFX gibt es nun keine Destruktoren, die von einem Programmierer direkt aufgerufen werden. Aber das bedeutet nicht, dass es keinen entsprechenden Mechanismus gibt. Die Beseitigung von Objekten erfolgt vollkommen automatisch durch die JVM über den so genannten Garbage Collector. Das erleichtert den Umgang mit Objekten erheblich und sorgt sowohl für eine höhere Stabilität als auch Sicherheit von Java- respektive JavaFX-Applikationen, da eine Applikation nicht durch vergessene Freigaben von Speicherbereichen kompromittiert werden kann. 109 Da es sich ja um eine Methode handelt.
155
Kapitel 4
4.1.4 Klassen- und Instanzelemente In einer Klassenspezifikation können so genannte Instanzelemente sowie Klassenelemente beschrieben werden. In beiden Fällen handelt es sich um die Attribute und die Methoden, die ein Objekt besitzen soll und die wie oben beschrieben notiert werden. Aber die beiden Typen unterscheiden sich im Zeitpunkt ihrer Existenz und im möglichen Zugang.
Instanzelemente Instanzattribute und Instanzmethoden sind die Elemente, die erst in einer konkret erzeugten Instanz existieren und erst dort verwendet werden können. Sie gehören damit explizit zu einer konkreten Instanz. Andere Instanzen, die aus der gleichen Klasse erzeugt werden, bekommen nicht mit, wann und wie eine Instanz auf ihrem Instanzelement operiert110. Für den Zugriff auf ein Instanzelement stellen Sie einen Bezeichner für das konkrete Objekt (eine Variable mit einer Referenz auf die Instanz als Inhalt) oder einen Stellvertreterbegriff (in Java und JavaFX lautet dieser wie schon erwähnt this111) voran.
Klassenelemente Im Gegensatz zu Instanzelementen existieren Klassenelemente grundsätzlich bereits in der Klasse selbst. Das bedeutet auch dann, wenn noch kein Objekt konstruiert wurde. Klassenattribute (auch statische Attribute genannt) sind Attribute, die zu einer Klasse selbst und nicht zu einem spezifischen Objekt gehören. Alle Instanzen einer Klasse haben gemeinsam Zugriff auf statische Attribute, die zudem unabhängig davon existieren, ob es von der Klasse kein, ein oder mehrere Instanzen gibt. Vollkommen analog sind Klassenmethoden (auch statische Methoden genannt) solche Methoden, die unabhängig von einem Objekt der Klasse ausgeführt werden können. Der Zugriff auf Klassenelemente erfolgt durch das Voranstellen des Klassennamens anstelle des Namens eines Objekts. Innerhalb einer Klasse kann man auf den Klassennamen auch verzichten, wenn man Klassenelemente der eigenen Klasse ansprechen möchte.
> >
>
HINWEIS
Statische Attribute und Methoden ähneln in gewisser Weise globalen Variablen und globalen Funktionen in prozeduralen Programmiersprachen. Statische Klassenelemente sind jedoch im Unterschied zu diesen dem Namensraum der Klasse zugeordnet. Sie sind also auf die Klasse und ihre Instanzen beschränkt und existieren nicht in anderen Klassen.
110 Also ob sich beispielsweise der Wert einer Instanzvariablen in einem Objekt ändert. 111 Dieser Begriff wurde wie gesagt schon bei der Besprechung der Operatoren in JavaFX im letzten Kapitel kurz beschrieben.
156
OOP in JavaFX Script
4.2 Allgemeines zum Mechanismus der Vererbung Wenn man in der OOP gemeinsame Eigenschaften und Fähigkeiten von Objekten in Klassen zusammenfassen möchte (eine sprichwörtliche Klassifizierung), wird man neben diesen Gemeinsamkeiten von Objekten oft auch trennende Unterschiede bemerken. Wenn Sie beispielsweise eine Reihe von verschiedenen Tieren wie Schafe, Kühe und Schweine (also konkrete Objekte) klassifizieren wollen, werden Sie durchaus eine Menge Gemeinsamkeiten entdecken. Aber eben auch Unterschiede. Es scheint sinnvoll zu sein, alle Gemeinsamkeiten der unterschiedlichen Objekte in einer Art Oberklasse, Basisklasse oder Superklasse für alle Tiere zusammenzufassen. Ein Objekt vom Typ Schaf gehört zu dieser Oberklasse. Genauso wie ein Schwein oder eine Kuh. In der Tat ist es so, dass gemeinsame Erscheinungsbilder in der objektorientierten Philosophie in einer möglichst hohen Klasse zusammengefasst werden. Erst wenn Unterscheidungen möglich bzw. notwendig sind, die nicht für alle Mitglieder einer Klasse gelten, werden Untergruppierungen – untergeordnete Klassen (so genannte Unterklassen oder Subklassen) – gebildet. Vererbung bezeichnet nun eine Verbindung zwischen einer Superklasse bzw. mehreren Superklassen und einer oder mehreren anderen Klassen, um Attribute und Methoden der Superklasse(n) mithilfe einer Klassenbeziehung in der bzw. den Subklasse(n) wieder verwenden zu können. Die Bestandteile einer Superklasse werden in die Subklassen übertragen und dort gegebenenfalls modifiziert. 112 113 Diese Vererbung geht über sämtliche Nachkommen einer Klasse, sofern man nicht mit geeigneten Mechanismen eine weitere Vererbung ab einer gewissen Ebene verhindert.
> >
>
HINWEIS
In der Theorie der Objektorientierung gibt es sowohl Einfachvererbung (englisch Single Inheritance) als auch Mehrfachvererbung (englisch Multiple Inheritance). In dem Konzept der Einfachvererbung gibt es für eine Subklasse immer nur genau eine direkte Superklasse. Eine Superklasse kann jedoch eine beliebige Anzahl an Subklassen haben (eine so genannte 1:n-Beziehung). Wenn eine Subklasse jedoch unmittelbar von mehreren Superklassen abgeleitet werden kann, nennt man dieses Mehrfachvererbung (eine so genannte n:m-Beziehung). Beim Konzept der Vererbung zeigt sich nun ein gravierender Unterschied zwischen Java und JavaFX Script. In Java gibt es nur Einfachvererbung! JavaFX hingegen unterstützt Mehrfachvererbung112! Allerdings stellt JavaFX keine Mechanismen wie abstrakte Klassen und vor allem Schnittstellen bereit, die in Java die Beschränkung auf Einfachvererbung weitgehend kompensieren113. Und zudem wird man in JavaFX in der Regel keine komplexen APIs aus Klassen aufbauen, sondern auf JavaAPIs zurückgreifen. Damit ist das Gesamtkonzept nicht komplexer als in Java. 112 Was ein wichtiger Punkt ist, der überzeugte Java-Programmierer am Sinn der Welt zweifeln lässt. Immer und immer wieder wurde gepredigt, wie schlimm doch Mehrfachvererbung sei und was für ein Fortschritt Java gebracht hätte, nur Einfachvererbung zu gestatten, und dann das! 113 Schnittstellen werden in Java auch Mehrfachvererbung Light genannt.
157
Kapitel 4
4.2.1 Generalisierung und Spezialisierung Subklassen sind als Spezialisierung einer Superklasse zu verstehen. Ein Schaf ist immer auch ein Tier – genau genommen ein Spezialfall eines Tiers. Umgekehrt ist die Superklasse eine Generalisierung beziehungsweise Verallgemeinerung der Subklasse (ein Schaf und ein Schwein sind auch Tiere).
> >
>
HINWEIS
Generalisierung und Spezialisierung stellen in der OOP gegensätzliche Sichtweisen auf die gleiche Beziehung dar.
4.2.2 Vererbung in Java sowie JavaFX mit extends Wenn man in Java als auch JavaFX eine Klasse explizit als Subklasse einer Klasse angeben will, wird das mit dem Schlüsselwort extends erfolgen, das hinter dem Bezeichner der Klasse notiert wird und dem die Klasse folgt, die als Superklasse dienen soll. In JavaFX können Sie auch eine kommatagetrennte Liste als Klassen angeben, die als Superklassen dienen sollen. Durch die Erweiterung einer Superklasse machen Sie aus Ihrer Klasse zuerst eine Art Kopie dieser Klasse und ermöglichen gleichzeitig Veränderungen an dieser neuen Kopie.
java.lang.Object In Java stammen alle Klassen von einer zentralen Superklasse Object ab, die im Paket java.lang zu finden ist. Diese stellt alle Grundfunktionalitäten eines rudimentären Objekts bereit. Wenn Sie in einer Java-Klasse keine explizite Superklasse mit extends angeben bedeutet das immer, dass die Klasse unmittelbar von java.lang.Object abgeleitet ist.
> >
>
HINWEIS
Die genaue Syntax der Vererbung in einer JavaFX-Klasse sehen Sie etwas weiter unten, wenn wir besprechen, wie in JavaFX konkret Klassen aufgebaut werden (siehe Seite 167).
4.3 Pakete und die import-Anweisung An verschiedenen Stellen in diesem Buch war bereits von Paketen die Rede. Pakete (engl. Packages) sind in Java beziehungsweise JavaFX – vereinfacht – die objektorientierte Abbildung von Verzeichnissen, in die zusammengehörende Klassen und Schnittstellen einsortiert werden können.
158
OOP in JavaFX Script
> >
>
HINWEIS
Pakete sind in Java und JavaFX also Gruppierungen von Klassen und Schnittstellen eines Verzeichnisses.
Pakete stellen das Java-Analogon zu Bibliotheken vieler anderer Computersprachen dar. Oder man kann es auch so sehen, dass Pakete zur Organisation von Klassen bzw. Schnittstellen und zur Vermeidung von Namenskonflikten dienen und daher insbesondere beim Aufbau von Bibliotheken genutzt werden. Die Verzeichnisstrukturen enthalten im Quelltext eine Darstellung über Bezeichner, die den physikalischen Verzeichnisnamen entsprechen. Der Zugriff auf Verzeichnisse und Unterverzeichnisse erfolgt gemäß der allgemeinen Regeln bei Objekten über die Punktnotation, etwa java.util. Dabei steht der Bezeichner java für ein Verzeichnis gleichen Namens und util spezifiziert darin ein Unterverzeichnis. Also steht java.util.Date für die Klasse Date im Verzeichnis util, das sich wiederum in einem Verzeichnis java findet. Vollkommen analog sind die Zugriffe auf die speziellen JavaFX-Pakete innerhalb des Hauptpakets javafx und die darin enthaltenen Klassen zu sehen. Etwa javafx.ui.Frame.
Abbildung 4.1: Die Datei Frame.fx wird über die Paketstruktur javafx.ui zur Verfügung gestellt
159
Kapitel 4
> >
>
HINWEIS
Wenn Sie sich die bisherigen Beispiele ansehen, erkennen Sie dort mehrfach bereits den Zugriff per Punktnotation auf Paketstrukturen und darin enthaltene Klassen.
4.3.1 Die Suche nach Paketen und der Klassenpfad Nun stellt sich aber die Frage, wo beispielsweise das Java-Standardverzeichnis java oder das Hauptpaket von JavaFX mit Namen javafx selbst zu finden sind? Wie findet das Java-System sozusagen den Einstieg? Die Antwort ist zweigeteilt. Zum einen sind die Orte, wo sich Java- und FX-Standardklassen in Form von komprimierten .jar-Archiven befinden, im Betriebssystem eingetragen114 und zum anderen gibt es den so genannten Klassenpfad oder classpath. Schauen wir uns das Konzept aber etwas genauer an. Wenn Sie in einer Java- oder JavaFX-Applikation auf andere Klassen respektive im Fall von JavaFX auf .fx-Dateien zugreifen wollen, wird das Java-System zuerst in dem aktuellen Paket (Verzeichnis) nach den passenden Dateien für diese Klassen suchen. Werden die Klassen dort nicht gefunden, sucht das Java-System in den Bibliotheken der Laufzeitumgebung, die bei der Installation von Java beziehungsweise JavaFX angelegt und im Betriebssystem registriert wurden, nach den Klassen und im Fall von JavaFX auch .fx-Dateien. Ist die Suche an diesen Stellen nicht von Erfolg gekrönt, wird auf einen so genannten Klassenpfad (englisch Classpath) zurückgegriffen. Dieser Klassenpfad besteht standardmäßig nur aus dem aktuellen Verzeichnis, kann aber auch gezielt um bestimmte Verzeichnisse erweitert werden.
> >
>
HINWEIS
Die Suche nach Klassen ist eine rein physische Suche nach .class-Dateien und im Fall von JavaFX zusätzlich .fx-Dateien, die auch in gepackten Verzeichnissen (.jar-Dateien) durchgeführt wird.
4.3.2 Zugriff auf Klassen und Schnittstellen in Paketen und die import-Anweisung Wenn Sie im Rahmen einer Java- oder JavaFX-Applikation eine Klasse in einem bestimmten Paket benötigen, können Sie die Klasse vollqualifiziert notieren. Das bedeutet, Sie notieren alle Pakete, in der sie enthalten ist, und dann den Namen der Klasse.
114 Wo das genau ist, müssen wir als Programmierer nicht einmal wissen.
160
OOP in JavaFX Script
Beispiel: javax.swing.JButton; Listing 4.4: Eine vollqualifizierte Angabe einer Klasse
Import einer Klasse Mit einer solchen vollqualifizierten Notation wird jedoch die Lesbarkeit des Quelltexts115 nicht gerade gut und vor allem der Tippaufwand für sich wiederholende Quelltextpassagen sehr hoch – insbesondere wenn man an zahlreichen Stellen Dateien aus einem Verzeichnis116 benötigt. Dies macht eine einfachere und schnellere Technik notwendig – das Importieren von Klassen und Paketen, was in Java bzw. JavaFX über die import-Anweisung erfolgt. Diese Anweisungen müssen ganz am Beginn eines Quelltextes notiert werden.
> >
>
HINWEIS
Eine import-Anweisung dient in Java bzw. JavaFX in der Tat ausschließlich dazu, Java-Klassen im Quellcode über einen verkürzten Namen innerhalb der aktuellen Bezugsklasse zugänglich zu machen und damit den Code zu vereinfachen bzw. zu verkürzen. Sie ist – trotz des irreführenden Namens – kein echter Import, der eine Klasse einliest (wie es etwa in C mit einer include-Anweisung gemacht wird). Deshalb können Sie in eine Applikation auch beliebig viele Pakete und Klassen importieren. Der resultierende Bytecode wird weder größer noch sonst ineffektiver. Nicht explizit benötigte Klassen werden vom Compiler wegoptimiert. Das nennt man type import on demand.
Sie können eine Klasse importieren, indem Sie die gesamte Punktnotation (das bedeutet die Angabe des Pakets, zu dem sie gehört, und die Klasse selbst) am Anfang einer Datei mit dem Schlüsselwort import angeben. Danach können Sie im folgenden Quelltext die Klasse direkt mit ihrem Namen ansprechen, ohne den vollqualifizierten Pfad notieren zu müssen. Beispiel: import java.awt.Date; .... var a = new Date(); Listing 4.5: Import von einer Klasse, um sie im folgenden Quelltext ohne vollständigen Pfadnamen ansprechen zu können
115 Besonders bei sehr umfangreichen Quelltexten. 116 Oder anders gesagt – Klassen aus einem Paket.
161
Kapitel 4
!
!
!
ACHTUNG
Es gibt bei jeder Java-Applikation ein Java-Paket, das Sie nie explizit importieren müssen. Das ist das Paket java.lang. Dieses Paket wird vom Laufzeitsystem immer automatisch importiert und stellt über die darin enthaltenen Klassen die Basis des gesamten Java-Konzepts dar. Darin finden Sie so wichtige Klassen wie Object, System oder String. Aber auch Wrapper-Klassen zur Konvertierung und die Klasse System sind dort enthalten. Das bedeutet also, dass Sie alle diese Klassen in dem Paket in einer Java-Applikation immer direkt über die verkürzte Notation ansprechen können. Das gilt nicht für eine JavaFX-Applikation! Hier müssen auch Klassen aus java.lang bzw. das gesamte Paket explizit importiert werden, wenn Sie die verkürzte Schreibweise verwenden wollen.
Import mehrerer Klassen aus einem Paket Wenn Sie mehrere Klassen aus einem Paket benötigen, arbeitet man sinnvollerweise mit Platzhaltern. Mittels einer solchen Wildcard – dem Stern * – kann ein ganzes Paket auf einmal importiert werden. Das geschieht wieder durch die import-Zeile, wobei nur der Klassenname durch den Stern ersetzt wird. Danach können Sie alle Klassen aus dem Paket direkt über ihre Namen ansprechen.
!
!
!
ACHTUNG
Das Sternchen importiert jedoch keine (!) untergeordneten Pakete. Um also alle Klassen einer komplexen Pakethierarchie zu importieren, müssen Sie explizit auf jeder Hierarchieebene eine importAnweisung erstellen.
4.3.3 Namenskonventionen und Standardpakete Es gibt nun im Rahmen von Java respektive JavaFX einige Namenskonventionen für Pakete. Die Standardklassen von Java und JavaFX sind in eine Paketstruktur eingeteilt, die an das Domain-System von Internetnamen angelehnt ist. Dabei sollte jeder Anbieter von eigenen Java- und JavaFX-Paketen diese nach seinem DNS-Namen strukturieren, nur in umgekehrter Reihenfolge.
> >
>
HINWEIS
Die Abkürzung DNS steht für Domain Name System. DNS-Namen sind Internet-Adressen wie www.javafx-buch.de, die bei einer Verwendung in einem Programm wie dem Browser in die zugehörige IP-Adresse umgewandelt werden.
Wenn etwa einer Firma RJS der DNS-Name www.rjs.de gehört und sie Java-Pakete bereitstellt, sollte die Paketstruktur mit de.rjs beginnen. Eventuelle Unterpakete sollten darunter angeordnet werden. Selbst offiziell in dem Standard-API von Java enthaltene Fremdpakete halten sich daran (etwa org.omg.CORBA oder org.w3c.dom). Einzige
162
OOP in JavaFX Script
(offizielle) Ausnahme sind die Klassen und Schnittstellen, die im Standardumfang einer Java-respektive JavaFX-Installation enthalten sind. Diese beginnen mit java oder javax (Java) oder mit javafx (JavaFX).
!
!
!
ACHTUNG
Die Einhaltung dieser Vorschläge zur Benennung von eigenen Paketstrukturen ist nun nicht zwingend. Nur kann die Nichtbeachtung dazu führen, dass es in größeren Projekten oder mit anderen Projekten zu Namenskonflikten kommt.
Bei der Auswahl der Namen für Pakete gelten ansonsten nur wieder die üblichen Regeln für Token in Java bzw. JavaFX. Grundsätzlich werden Paketbezeichner kleingeschrieben bzw. nur die Anfangsbuchstaben ab dem zweiten Begriff (bei zusammengesetzten Begriffen), aber das ist nur eine Konvention. Allerdings müssen Sie beachten, dass das dann auch bei den Verzeichnisnamen so eingehalten wird. Das erfolgt analog zu Dateinamen, wobei Groß- und Kleinschreibung natürlich auch relevant ist.
> >
>
HINWEIS
Die Einhaltung von Paketstrukturen und entsprechenden Namenskonventionen ist für JavaFXProjekte nicht ganz so wichtig wie für Java-Projekte. Sie erstellen ja in der Regel keine API-Strukturen, die mit anderen Strukturen kooperieren müssen, sondern meist nur den reinen eigenständigen Applikationscode. Dennoch spricht natürlich nichts dagegen, dass Sie sich daran halten.
4.4 Die konkrete Verwendung von Java-Klassen und JavaFX-Standardklassen in JavaFX Schauen wir uns nun konkret an, wie in JavaFX-Applikationen Java-Klassen aus dem Standard-API verwendet werden können. Das bedeutet, wir erzeugen nun Objekte aus Standardklassen bzw. verwenden Klassenelemente aus dem Standard-API.
4.4.1 Die Java-Notation Die erste Notation wird Java-Programmierern vertraut sein, denn es unterscheidet sich in nur wenigen Syntaxdetails (und im Grunde rein in gar nichts bezüglich des Konzepts) von reinem Java. Der folgende Code zeigt ein Beispiel, wie Sie in einer JavaFXApplikation aus einer Standardklasse des Swing-Konzepts ein Fenster mit einer Schaltfläche erzeugen können (javafxapp3): 01 02 03 04
var frame = new JFrame(); var button = new JButton("Drueck mich fest - gaaanz fest"); frame.getContentPane().add(button); button.addActionListener(new ActionListener() { operation actionPerformed(event) { System.exit(0); } }); frame.pack(); frame.setVisible(true);
Listing 4.6: Der Import und die Verwendung von Java-Klassen in einer JavaFX-Applikation
Wenn Sie das Beispiel ausführen, erhalten Sie ein kleines Fenster, in dem nur eine Schaltfläche zu sehen ist.
Abbildung 4.2: Die einfache Applikation zeigt nur eine Schaltfläche
Die Funktionalität dieser Applikation ist recht simpel. Mit einem Klick auf die Schaltfläche wird das Programm einfach beendet. Das erfolgt über die Anweisung System. exit(0); in Zeile 11 – das ist in diesem Fall der Aufruf einer Klassenmethode, die von der Klasse System aus dem Paket java.lang bereitgestellt wird. Damit diese Funktionalität sowie die Erzeugung des Fensters samt Schaltfläche allerdings überhaupt vorhanden sind, wurden jedoch mehrere Klassen des Standard-APIs von Java verwendet, die am Beginn des Quelltextes importiert werden. In der Zeile 1 werden die Klasse JFame und in der Zeile 2 die Klasse JButton importiert. Beide finden sich in dem Paket javax.swing. Durch den Import können Sie im folgenden Quelltext über die verkürzte Angabe auf die Klassen zugreifen (Zeile 6 und 7). In Zeile 3 importieren Sie die Klasse ActionListener aus dem Paket java.awt.event. Diese Klasse stellt in Java eine Reaktionsmöglichkeit zur Verfügung. Der verkürzte Zugriff auf die Klasse erfolgt in Zeile 9. Der vierte Import in Zeile 4 importiert die angesprochene Klasse System aus dem Paket java.lang. Dieses ist das Basispaket der gesamten Java-Technologie und stellt neben Methoden zum Beenden einer Applikation auch solche für die Ausgabe der Konsole und viele weitere Grundlagen, die in jeder typischen Applikation vonnöten sind, zur Verfügung. Achtung: in JavaFX müssen Sie das Paket – wie schon erwähnt – explizit importieren, was in reinem Java nicht der Fall ist!
164
OOP in JavaFX Script
In Zeile 6 verwenden wir einen Konstruktor zum Erzeugen eines Objekts des Typs javax.swing.JFrame : var frame = new JFrame();
Das Objekt frame repräsentiert ein GUI-Fenster. In der Zeile 7 wird der Konstruktor der Klasse JButton zum Erzeugen eines Objekts verwendet: var button = new JButton("Drueck mich fest - gaaanz fest");
Dieses Objekt steht für eine Schaltfläche. In Zeile 8 wird mit frame.getContentPane().add(button); die Schaltfläche dem Fenster hinzugefügt. Die Zeilen 9 bis 13 dienen dazu, die Reaktion auf den Klick auf die Schaltfläche zu implementieren. Zeile 14 optimiert die Größe des Fensters so, dass alle enthaltenen Komponenten zu sehen sind, aber kein Platz verschwendet wird (frame.pack();) und Zeile 15 zeigt das Fenster dann an (frame.setVisible(true);).
4.4.2 Die spezielle JavaFX-Notation – die deklarative Erzeugung Das letzte Beispiel hat eine Art der Programmierung (oder besser des Designs) verwendet, die aus der klassischen Java-Programmierung stammt und in JavaFX zur Erstellung einer GUI (und allgemein Objekten aus JavaFX-Klassen) eigentlich nicht verwendet werden soll. Zumindest rät Sun zu einem anderen Design. Sun hat mit JavaFX hierzu speziell eine neue Art der Syntax samt einem eigenen API eingeführt, die insbesondere Programmierern ohne fundierten Java-Background die Erstellung von Klassen bzw. Objekten erleichtern soll. Denn trotz der recht weitgehenden Erklärung oben sind insbesondere Java-Neulingen ganz sicher noch nicht alle Details klar. Insbesondere würde sicher das Erstellen von eigenen Applikationen ohne vertiefende Grundlagen kaum möglich sein. Die nachfolgende Umstrukturierung des Beispiels zeigt, wie man so ein JavaFX-Programm eigentlich angehen sollte117. Es bewirkt genau das Gleiche wie die erste Variante, sollte aber nach der Idee hinter JavaFX sowohl kompakter als auch ohne vertiefende Java-Kenntnisse leichter nachzuvollziehen sein (javafxapp3a): 01 import javafx.ui.Frame; 02 import javafx.ui.Button; 03 import java.lang.System;
117 Dieses Listing haben wir im Laufe des Buchs schon einmal weitgehend analog gesehen.
165
Kapitel 4 04 05 Frame { 06 content: Button { 07 text: "Drueck mich fest - gaaanz fest" 08 action: operation() { 09 System.exit(0); 10 } 11 } 12 visible: true 13 } Listing 4.7: Die alternative Form, die in JavaFX als Standard verwendet werden soll
In den ersten Zeilen haben Sie wieder die Importanweisungen. Diese haben sich maßgeblich verändern. Statt den Swing-Klassen werden nun die korrespondierenden Klassen des JavaFX-APIs verwendet. In den Zeilen 5 bis 13 finden Sie nun eine Beschreibung für eine Klasse in JavaFX. Diese Zeilen bewirken, dass zur Laufzeit ein Objekt aus der Klasse erzeugt wird, das einem Swing-Fenster entspricht. Allerdings sehen Sie nirgends einen Konstruktor oder den new-Operator. Man redet hier von einer so genannten deklarativen Erzeugung eines Objekts, die wir noch genauer beleuchten. In Zeile 5 finden Sie den Bezeichner der JavaFX-Standardklasse javafx.ui.Frame für ein Swing-Fenster. Wenn er im Listing notiert wird, können Sie in einem nachfolgenden Block einfach die Werte für alle verfügbaren Attribute bzw. Eigenschaften für eine Instanz dieser Klasse spezifizieren. Dazu notieren Sie den Wert per Doppelpunkt abgetrennt hinter dem Attribut. In unserem Fall geben wir einen Wert für content (also den Inhalt des Fensters) an. Der Inhalt des Fensters ist eine Schaltfläche (Zeile 6 – content: Button). Die zweite Eigenschaft der Klasse javafx.ui.Frame, die hier in dem Beispiel mit einem Wert versehen wird, ist visible. Diese ist ganz einfach für die Sichtbarkeit des Objekts verantwortlich. Zeile 12 sorgt dafür, dass das Fenster mit der Schaltfläche angezeigt wird (visible: true). Die Beschriftung des Buttons wird mit Zeile 7 über die Eigenschaft text der Klasse javafx.ui.Button angegeben (text: "Drueck mich fest - gaaanz fest"). Beachten Sie, dass wir uns hier in einem Block befinden, der zu der Klassennotation von javafx.ui.Button gehört. Und die Reaktion auf einen Klick auf die Schaltfläche wird in Zeile 8 über die Eigenschaft action festgelegt (action: operation()). Hier wird eine Operation beziehungsweise Prozedur zugeordnet. Wenn also ein Klick auf die Schaltfläche erfolgt, wird die Applikation mit System.exit(0); (Zeile 9) beendet. Auch hier befinden wir uns in dem Block, der zu der Klassennotation von javafx.ui.Button gehört.
166
OOP in JavaFX Script
> >
>
HINWEIS
Diese Notation mag vor allem Java-Programmierern seltsam vorkommen, ist aber sehr strikt und klar. Wir vertiefen sie bei den folgenden Ausführungen.
4.5 Klassen und Objekte in JavaFX selbst erzeugen Wir haben im vorherigen Abschnitt Klassen aus dem Standard-API von Java respektive JavaFX verwendet. Nun schauen wir, wie Sie in JavaFX selbst Klassen schreiben und daraus dann Objekte erzeugen118.
4.5.1 Eine eigene Klasse schreiben In der Syntax von JavaFX verwenden Sie wie in Java zum Deklarieren einer Klasse das Schlüsselwort class, dem der Bezeichner der Klasse folgt. In geschweiften Klammern folgt – abgesehen von einer Vererbungsangabe (siehe Seite 181) – eine Liste mit Attributen, Funktionen und Operationen, die jeweils mit einem Semikolon beendet werden. Hier ist ein Beispiel für die Definition einer eigenen Klasse in JavaFX: 01 class Person { 02 attribute name: String; 03 attribute eltern: Person* inverse Person.kinder; 04 attribute kinder: Person* inverse Person.eltern; 05 attribute partner:Person; 06 function getFamilienEinkommen(): Number; 07 function getAnzahlKinder(): Number; 08 operation verheiratet(partner: Person); 09 } Listing 4.8: Eine Klassendefinition in JavaFX
Die Klasse stellt in beliebiger Reihenfolge die Eigenschaften (Attribute) name, eltern, partner und kinder zur Verfügung sowie die Funktionen getFamilienEinkommen() und getAnzahlKinder() und die Prozedur verheiratet(). Beachten Sie, dass sowohl die Funktionen als auch die Prozeduren im klassischen OOP-Sprachgebrauch Methoden der Klasse darstellen, aber an dieser Stelle keine konkrete Implementierung aufweisen. Gehen wir die Syntaxdetails an.
118 Letzteres wird natürlich analog dem Erzeugen aus Standardklassen sein – aber wir wollen das Verfahren ja noch vertiefen.
167
Kapitel 4
4.5.2 Die Deklaration von Methoden Die Methoden einer JavaFX-Klasse werden in der Klassendeklaration nur in der Klasse verankert. Dabei wird für die Verankerung eine Signatur verwendet, die wie bei normalen Funktionen und Operationen aussieht. Nur handelt es sich bei dieser Verankerung um eine Angabe, die in etwa einer abstrakten Methodensignatur in Java entspricht (also ohne konkrete Implementierung, d. h. ohne Methodenkörper). Im Unterschied zu Java werden die konkreten Definitionen der Methoden außerhalb der Klassendeklaration notiert, wobei hier zusätzlich zur Kennzeichnung der Name der Klasse dem Methodennamen vorangestellt werden muss119!
> >
>
HINWEIS
Wer sich mit JavaScript auskennt, wird die Ähnlichkeit zum dortigen Prototyping erkennen. Interessanterweise wird Prototyping bei JavaScript als Ersatz für die echte Bildung von Klassen bezeichnet.
Sie könnten nun beispielsweise die Funktion getAnzahlKinder() wie folgt als Methode der Klasse Person außerhalb der Klassendeklaration notieren: function Person.getAnzahlKinder() { return sizeof this.kinder; } Listing 4.9: Die Deklaration der Methode außerhalb der Klasse
Beachten Sie den vorangestellten Bezeichner der Klasse beim Namen der Methode (in dem skizzierten Beispiel Person). Damit erkennt der Interpreter die Funktion als Methode dieser vorangestellten Klasse und unterscheidet sie von einer »gewöhnlichen« Funktion. Das Gleiche gilt natürlich auch für Operationen. Sie sollten sich nun auch an das letzte Kapitel erinnern. Funktionen im Sinn von JavaFX dürfen nur eine Reihe an Variablendeklaration und müssen eine return-Anweisung mit Rückgabewert enthalten. Das gilt natürlich auch dann, wenn diese Funktionen als Methoden einer Klasse eingesetzt werden. Wenn Sie in einer Methode weitergehende Funktionalität benötigen, greifen Sie auf Operationen bzw. Prozeduren zurück. Diese können im Gegensatz zu Funktionen in JavaFX eine beliebige Anzahl und Art an Anweisungen enthalten.
119 Auch hier sehen Sie einen Bruch zur strengen Kapselung von Objektinterna, wie es in der klassischen objektorientierten Programmierung (also in Java) unabdingbar ist.
168
OOP in JavaFX Script
> >
>
HINWEIS
Die Reihenfolge der Deklarationen der Klasse und der enthaltenen Methoden spielt keine Rolle. Das bedeutet, dass Sie die konkreten Methodenimplementierungen im Quelltext beliebig vor oder nach der Klassendeklaration notieren können.
Leider kontrolliert der JavaFX-Interpreter beim Ausführen einer Applikation nicht, ob für sämtliche angegebenen Methoden in einer Klasse auch wirklich konkrete Implementierungen vorliegen120.121
!
!
!
ACHTUNG
Sowohl die Angabe der Parameter als auch des Rückgabetyps sind bei der Verankerung der Operationen und Funktionen in der Klassendeklaration zwingend. Sie können jedoch bei der konkreten Ausprogrammierung außerhalb der Klassendeklaration in der Methodensignatur auch weggelassen werden! Sie können sie aber dort auch ebenso noch einmal wiederholen. Dann müssen sie freilich mit den Angaben in der Klassendeklaration übereinstimmen. Ich würde auf Grund der besseren Wartbarkeit auf jeden Fall empfehlen, sich entweder für das konsequente Weglassen oder das konsequente Beibehalten (was aus meiner Sicht in der Praxis vorzuziehen ist) zu entscheiden121. Auf keinen Fall sollten die beiden Möglichkeiten in einem Projekt oder gar einer Quelltextdatei gemischt werden. In dem bald folgenden vollständigen Beispiel machen wir das nur zu Demonstrationszwecken. Sie sehen also die unterschiedlichen Varianten in einem vollständigen Listing.
4.5.3 Die Deklaration von Attributen Attribute eines Objekts werden in JavaFX in einer Klasse unter Verwendung des Schlüsselworts attribute deklariert. Diesem folgen der Name des Attributs, ein Doppelpunkt und der Typ des Attributs.
Optional – die Kardinalität Optional kann dem Typ des Attributs eine Kardinalität folgen. Wenn eine solche Kardinalität mit mehr als einem Vorkommen angegeben wird, werden diese mehrfach vorkommenden Attribute als Datenfelder repräsentiert. Die einzelnen Attribute können dann wie jedes Datenfeld über den []-Operator verwendet und das Datenfeld mit den Operatoren insert und delete modifiziert werden.
120 Zumindest nicht in der Version, die dem Buch zugrunde liegt. 121 Ich bin überhaupt nicht glücklich mit solchen »sowohl-als-auch«-Konstruktionen. Mir ist es lieber, wenn es nur eine Möglichkeit gibt, und die wird konsequent gefordert.
169
Kapitel 4
Optional – die Klausel inverse Ebenso optional wie die Angabe der Kardinalität ist die Klausel inverse, die bei Verwendung am Ende der Anweisung notiert wird. Diese Angabe gibt eine bidirektionale Beziehung zu anderen Attributen in der Klasse an. Wenn diese Klausel verwendet wird, wird der JavaFX-Interpreter automatisch Updates des inversen Attributs (Einfügen oder Löschen oder Ersetzen – das hängt ab von der Art des Updates und der Kardinalität der Attribute) durchführen, wann immer der Wert des Attributs modifiziert wird. Ein Semikolon beschließt die Deklaration jedes Attributs, was ja für jede Anweisung gilt.
> >
>
HINWEIS
Die Verwendung inverser Beziehungen ist nicht ganz unproblematisch bezüglich des Designs einer Applikation. Es kann leicht ein ziemlich kompliziertes Beziehungsgeflecht zwischen Klassen/Objekten aufgebaut werden, das schwer zu durchschauen bzw. zu warten ist. Sie sollten dieses Attribut deshalb nur sparsam und mit Vorsicht einsetzen und vor allem die bidirektionalen Beziehungen gut dokumentieren. Beachten Sie dazu auch das Beispiel Seite 181.
Ein Schema für eine Attributdeklaration So sieht also das Schema für eine Attributdeklaration aus: attribute AttributName : AttributeTyp [Kardinalität] [inverse KlassenNamen.InverseAttributName]; Listing 4.10: Das Schema für eine vollständige Attributdeklaration
Initialisierungswerte für Attribute bei der Deklaration In JavaFX ist es möglich Initialisierungswerte für Attribute zu deklarieren. Da man in der eigentlichen Klassendeklaration nur Verankerungen vornimmt, muss man die Initialisierungen außerhalb der Klassendeklaration vornehmen. Die Initialisierer werden im Kontext des neu erzeugten Objekts in der Reihenfolge ausgewertet, in der die Attribute in der Klassendeklaration spezifiziert werden. Beispiel (initialisierungattribute): 01 02 03 04 05 06 07 08
170
import java.lang.System; class X { attribute a: Number; attribute b: Number; } attribute X.a = 10;
OOP in JavaFX Script 09 10 11 12 13
attribute X.b = 42; var x = new X(); System.out.println(x.a); // Ausgabe 10.0 System.out.println(x.b); // Ausgabe 42.0
Listing 4.11: Initialisierungen von Attributen
Die Attribute der Klasse X werden in den Zeilen 8 und 9 initialisiert.
> >
>
HINWEIS
Beachten Sie auch die kleine automatische Konvertierung des Datentyps. Aus einem ganzzahligen Literal wurde ein Gleitkommatyp. Das Verhalten werden Sie in JavaFX häufiger beobachten können.
4.6 Objektliterale und die deklarative Erzeugung von Objekten in JavaFX Grundsätzlich122 werden – wie bereits mehrfach erwähnt – Objekte in Java mittels eines Konstruktors erzeugt. In JavaFX gibt es jedoch noch einen anderen Weg zur Erzeugung von Objekten, der nach den Aussagen von Sun insbesondere Einsteigern leichter fallen soll. Diesen haben wir schon kurz angesprochen und wollen ihn jetzt vertiefen. JavaFX-Objekte können unter Verwendung einer deklarativen Syntax allokiert123 werden. Dabei wird im Quelltext einfach der Name einer verfügbaren Klasse notiert, dem ein Block mit geschweiften Klammern folgt. Darin befindet sich einfach eine Liste mit Attributinitialisierungen, die einfach nur durch Whitespace getrennt werden. Wenn man das deklarativ erzeugte Objekt an anderer Stelle im Quelltext ansprechen möchte, kann man es124 während der Erzeugung einer Variablen zuweisen. Dann steht vor dem Name der Klasse der Variablenbezeichner und ein Gleichheitszeichen (der Zuweisungsoperator).
> >
>
HINWEIS
Mehrere Attributinitialisierungen können auch in einer Quelltextzeile notiert werden. Nur ist es oft übersichtlicher, wenn jede einzelne Attributinitialisierung in einer eigenen Zeile steht.
122 Mit ganz wenigen Ausnahmen – hauptsächlich Arrays, die indirekte Erzeugung von Strings über Zuweisung eines Literals und Factories (die aber indirekt Konstruktoren verwenden). 123 Das bedeutet, dass ein Objekt erzeugt und Speicher reserviert wird. 124 Oder genauer – eine Referenz auf das Objekt.
171
Kapitel 4
Jeder dieser Initialisierer besteht aus dem Namen eines Attributes, gefolgt von einem Doppelpunkt und einem Ausdruck, der den Wert des Attributs definiert. Man erzeugt bei einer solchen Syntax das Objekt unter Verwendung eines so genannten Objektliterals, was geübte Java-Programmierer an den Fall der Erzeugung eines Stringobjekts mit einem Stringliteral erinnern sollte.125
> >
>
HINWEIS
Der Ausdruck zum Zuweisung eines Werts für ein Attribut kann sogar inkrementell verarbeitet werden, was gleich noch genauer besprochen wird (siehe Seite 189).
Hier sehen Sie ein Beispiel für eine solche deklarative Erzeugung eines JavaFX-Objekts aus einer Klasse mit Namen Person. So könnte die Klasse aussehen: 01 class Person { 02 attribute name: String; 03 attribute alter: Number; 04 } Listing 4.12: Eine JavaFX-Klasse
Und das wäre eine deklarative Erzeugung: 01 var sohn = Person { 02 name: "Felix" 03 alter: 7 04 }; Listing 4.13: Deklaratives Erzeugen eines Objekts und Zuweisung der Referenz auf das Objekt zu der Variablen sohn
Die »normale« Java-Syntax zum Allokieren eines Objekts wird aber auch unterstützt. Das würde in diesem Fall so aussehen: var sohn = new Person(); Listing 4.14: Erzeugen eines Objekts mit der klassischen Java-Syntax
Jetzt hängt es aber von der Existenz eines passenden Konstruktors ab (ein so genannter parametrisierter Konstruktor), ob Sie beim Anlegen des Objekts bereits den Eigenschaften der Instanz Werte zuweisen können oder das erst im Nachhinein tun.
125 Inkrementell bedeutet sukzessive, stückchenweise voranschreitend. Man macht also mehrere kleine Arbeitsschritte statt einem großen.
172
OOP in JavaFX Script
Letzteres würde so aussehen: sohn.name = "Florian"; Listing 4.15: Zuweisen eines Werts einer Objekteigenschaft nach der Erzeugung des Objekts
Im allgemeinen Fall haben nun Konstruktoren in JavaFX keine Parameter126, aber im Fall von Java-Klassen kann man natürlich Argumente an den Klassenkonstruktor weitergeben, wenn ein parametrisierter Konstruktor existiert (oder auch die deklarative Syntax verwenden). Das nachfolgende Beispiel (klasse3) zeigt das: 01 02 03 04 05 06 07 08 09 10 11 12 13
import java.util.Date; import java.lang.System; // Aufruf eines Java-Konstruktors var date1 = new Date(107, 11, 24); // Erstellen eines Datumsobjekts als Objektliteral var date2 = Date { month: 11 date: 24 year: 107 }; System.out.println(date1); System.out.println(date2);
Listing 4.16: Deklaratives Erzeugen eines Objekts mit Initialisierung als auch Anwendung der klassischen Java-Syntax mit einem parametrisierten Konstruktor
Sowohl die Zeile 5 als auch die Zeilen 7 bis 11 erzeugen ein Datumsobjekt. Diese sind zwar vom erzeugten Zeitpunkt nicht ganz identisch, da im Fall der Java-Syntax der Zeitpunkt 0 Uhr des angegebenen Tages und im Fall der deklarativen Erzeugung die aktuelle Uhrzeit des Erzeugungstags genommen wird, aber das kann man mit einem anderen Konstruktor mit Stunden, Minuten, Sekunden und Millisekunden auch gewährleisten.
4.6.1 Lokale Variablen in Objektliteralen In JavaFX kann man innerhalb eines Objektliterals lokale Variablen deklarieren. Solche Variablen sind nur im Bereich des Objektliterals selbst sichtbar. Zudem kann eine Variable, die auf das gerade initialisierte Objekt verweist, über das var-Schlüsselwort als eine Art Pseudo-Attribut deklariert werden.
126 Genau genommen arbeitet man wie gesagt in JavaFX sowieso gar nicht so gerne mit Konstruktoren.
import java.lang.*; class Person { attribute name: String; attribute eltern: Person* inverse Person.kinder; attribute kinder: Person* inverse Person.eltern; } var papa = Person { var: meinereiner name: "Ralph" var sohn1 = Person { name: "Felix" eltern: meinereiner } var sohn2 = Person { name: "Florian" eltern: meinereiner } kinder: [sohn1, sohn2] }; System.out.println(papa.kinder[0].name); System.out.println(papa.kinder[1].name);
Listing 4.17: Einsatz von lokalen Variablen
Die Klasse Person stellt drei Attribute zur Verfügung, die von außen zugänglich sind. In den Zeilen 8 bis 20 wird deklarativ aus dieser Klasse ein Objekt mit Namen papa erzeugt. In diesem Objekt gibt es mehrere lokale Variablen. Das sind meinereiner, sohn1 und sohn2. Diese Pseudo-Attribute können nicht von außen über das Objekt papa aufgerufen werden. Sie stehen aber innerhalb des Objekts zu Verfügung. Es gibt von außen nur einen Zugriff auf die Attribute name, eltern (ein Array – das sehen Sie an der Kardinalität) und kinder (ein weiteres Array). Das Beispiel gibt über das Datenfeld kinder die Namen der beiden Personen aus.
4.7 Ein vollständiges Beispiel mit eigener Klasse Schauen wir uns nun ein vollständiges und etwas umfangreicheres Skript mit JavaFX zur weiteren Verdeutlichung der bisherigen Ausführungen an. Darin finden Sie fast alle bisher in dem Kapitel besprochenen Techniken wieder. Lassen Sie sich nicht schrecken – das Beispiel ist recht lang, was aber im Wesentlichen auf die umfangreichen Kommentare zurückzuführen ist. Es sollte mit den bisherigen Ausführungen und den nachfolgenden Erklärungen gut zu verstehen sein und gibt
174
OOP in JavaFX Script
bereits einen recht vollständigen Einblick in die Art der objektorientierten Programmierung, wie man sie mit JavaFX durchführen sollte (klasse1): 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
// Notwendige Imports import java.util.Random; import java.lang.*; // Variablendeklarationen var papa : Person; var mama : Person; var sohn : Person; var tochter : Person; // Methodendeklarationen // Funktion getAnzahlKinder(), die in der folgenden Klasse Person als // Methode registriert ist – hier mit Wiederholung des Rückgabetyps function Person.getAnzahlKinder():Number { // Die Anzahl der Kinder - ergibt sich aus der Größe des Arrays return sizeof this.kinder; } // Funktion getFamilienEinkommen(), die in der Klasse Person als // Methode registriert ist – hier ohne Wiederholung des Rückgabetyps function Person.getFamilienEinkommen(){ // Zufällige Berechnung des Familieneinkommens // mit einem Standardmechanismus von Java // java.util.Random liefert einen Zufallsgenerator var zufall = new Random(); // Rückgabe eines zufälligen ganzzahligen Werts < 4000 return zufall.nextInt(4000); } // Die Operation weist einer Person einen Partner zu. Die // Operation ist in der Klasse Person als Methode registriert operation Person.verheiratet(partner: Person){ // Ausgabe einer Meldung System.out.println("Don't marry be happy."); // Zuweisung des Wertes von dem Parameter zu der // Eigenschaft partner des aktuellen Objekts // Dieses ist über this zugänglich this.partner = partner; } // Eine Klasse, um eine Person zu erzeugen class Person { // Attribute der Klasse attribute name: String; // Der Name der Person // Das Attribut eltern kann mehrfach vorkommen und auch fehlen // bidirektionale Beziehung zu kinder attribute eltern: Person* inverse Person.kinder; // Das Attribut kinder kann mehrfach vorkommen und auch fehlen
// bidirektionale Beziehung zu eltern attribute kinder: Person* inverse Person.eltern; // Das Attribut partner kann einmal vorkommen und auch fehlen attribute partner:Person; // Methoden - Funktionen function getFamilienEinkommen(): Number; function getAnzahlKinder(): Number; // Methoden - Operationen operation verheiratet(partner: Person); } /* Erzeugen von 4 Objekten vom Typ Person - die gesamte Familie */ // Erzeugen eines Objekts vom Typ Person, das über den Bezeichner // papa dann zur Verfügung steht papa = Person { // Das Attribut name bekommt einen Wert name: "Fred Feuerstein" // Das Attribut kinder vom Typ Person kann mehrfach vorkommen // Hier werden zwei Attribute erzeugt und mit Werten versehen kinder: [Person { name: "Bamm-Bamm" }, Person { name: "Pebbles" } ] }; // Erzeugen einer Person, die über den Bezeichner mama dann zur // Verfügung steht mama = Person{ // Das Attribut name bekommt einen Wert name: "Wilma Feuerstein" // Das Attribut kinder vom Typ Person kann mehrfach vorkommen // Hier werden zwei Attribute erzeugt und mit Werten versehen kinder: [Person { name: "Bamm-Bamm" }, Person { name: "Pebbles" } ] };
OOP in JavaFX Script 97 // Erzeugen einer Person, die über den Bezeichner sohn dann zur 98 // Verfügung steht 99 sohn = Person{ 100 // Das Attribut name bekommt einen Wert 101 name: "Bamm-Bamm Feuerstein" 102 // Das Attribut eltern vom Typ Person kann mehrfach vorkommen 103 // Hier werden zwei Attribute erzeugt und mit Werten versehen 104 eltern: 105 [Person { 106 name: "Fred" 107 }, 108 Person { 109 name: "Wilma" 110 } 111 ] 112 }; 113 114 // Erzeugen einer Person, die über den Bezeichner tochter dann zur 115 // Verfügung steht 116 tochter = Person{ 117 // Das Attribut name bekommt einen Wert 118 name: "Pebbles Feuerstein" 119 // Das Attribut eltern vom Typ Person kann mehrfach vorkommen 120 // Hier werden zwei Attribute erzeugt und mit Werten versehen 121 eltern: 122 [Person { 123 name: "Fred" 124 }, 125 Person { 126 name: "Wilma" 127 } 128 ] 129 }; 130 131 /* Der eigentliche Programmablauf, in dem mit den Eigenschaften und 132 Methoden der Objekte agiert wird */ 133 134 // Das Objekt papa bekommt einen Wert für die 135 // Eigenschaft partner zugewiesen 136 papa.verheiratet(mama); 137 138 // Zugriff auf name und partner (bzw. dessen Eigenschaft name) 139 // des Objekts papa. Zusammensetzen eines Ausgabe-Strings mit concat() 140 System.out.println( 141 papa.name . 142 concat( " ist nun verheiratet mit " . 143 concat(papa.partner.name) . 144 concat("."))); 145 146 // Zugriff auf die Methode getFamilieEinkommen() über das Objekt papa
// Zusammensetzen eines Ausgabe-Strings mit concat() System.out.println( "Die Familie Feuerstein verdient " . concat(papa.getFamilienEinkommen().toString()) . concat(" EUR.")); // Zugriff auf name und partner (bzw. dessen Eigenschaft name) // sowie die Methode getAnzahlKinder() des Objekts papa // Zusammensetzen eines Ausgabe-Strings mit concat() // Beachten Sie die verschiedenen Schachtelungen von concat() // - nur zu Demonstrationszwecken System.out.println( papa.name . concat(" und ") . concat(papa.partner.name) . concat( " haben " . concat(papa.getAnzahlKinder().toString()) . concat(" Kinder.") ) ); // Zugriff auf die Werte von name und eltern[0] (bzw. dessen // Eigenschaft name - das ist der Vater) des Objekts tochter // Zusammensetzen eines Ausgabe-Strings mit concat() // Beachten Sie die verschiedenen Schachtelungen von concat() System.out.println( "Der Papa von " . concat(tochter.name) . concat( " heisst " . concat(tochter.eltern[0].name) . concat(".") ) ); // Zugriff auf die Werte von name und eltern[1] // (bzw. dessen Eigenschaft name - das ist die Mutter) des Objekts sohn // Zusammensetzen eines Ausgabe-Strings mit concat() // Beachten Sie die verschiedenen Schachtelungen von concat() System.out.println( "Die Mama von " . concat(sohn.name) . concat( " heisst " . concat(sohn.eltern[1].name) . concat(".") ) );
Listing 4.18: Das Erstellen einer eigenen JavaFX-Klasse
178
OOP in JavaFX Script
Schauen wir uns zunächst die Ausgabe des Beispiels an: Don't marry be happy. Fred Feuerstein ist nun verheiratet mit Wilma Feuerstein. Die Familie Feuerstein verdient 390 EUR. Fred Feuerstein und Wilma Feuerstein haben 2 Kinder. Der Papa von Pebbles Feuerstein heisst Fred. Die Mama von Bamm-Bamm Feuerstein heisst Wilma. In den Zeilen 6 bis 9 werden vier Variablen vom Typ Person definiert. Dann finden Sie die Methodendeklarationen für die Klasse Person. Diese wird erst nach den Deklarationen für die Methoden definiert. Die Funktion getAnzahlKinder() (Zeile 14 – 17), die in der folgenden Klasse Person als Methode registriert ist, gibt die Anzahl der Kinder einer Person zurück – diese ergibt sich aus der Größe des Arrays, das Referenzen auf Objekte vom Typ Kinder speichert. Beachten Sie, dass in Zeile 14 in der Unterschrift der Methode der Rückgabetyp wiederholt wird: function Person.getAnzahlKinder():Number {
Die Funktion getFamilienEinkommen() (Zeile 20 bis 27), die ebenfalls in der Klasse Person als Methode registriert ist, liefert über eine zufällige Berechnung einen Wert für das Familieneinkommen der gedachten Familie, die aus den Klassen in diesem Beispiel aufgebaut wird. Beachten Sie, dass in Zeile 20 in der Unterschrift der Methode der Rückgabetyp hier nicht wiederholt wird: function Person.getFamilienEinkommen(){
Zum Berechnen des Zufallswertes kommt eine Klasse java.util.Random zum Einsatz, die eine Methode nextInt() zur Verfügung stellt. Ab Zeile 30 finden Sie eine Prozedur beziehungsweise Operation verheiratet(). Die Operation weist einer Person einen Partner zu und ist in der Klasse Person als Methode registriert. Sie geht bis zu Zeile 37. Ab Zeile 40 ist die Deklaration einer Klasse zu finden, um eine Person zu erzeugen. Die Attribute der Klasse sind ein Name für die Person, ein optionales Attribut eltern, das mehrfach vorkommen und auch fehlen kann und eine bidirektionale Beziehung zu kinder repräsentiert, und ein ebenfalls optionales Attribut kinder, das mehrfach vorkommen und auch fehlen kann und eine bidirektionale Beziehung zu eltern repräsentiert. Des Weiteren gibt es das Attribut partner, das einmal vorkommen und auch fehlen kann. Offensichtlich kann damit eine typische Ehe oder feste Beziehung samt Kindern beschrieben werden.
179
Kapitel 4
In den nächsten Zeilen des Quellcodes sind die konkreten Verankerungen für die Methoden getFamilienEinkommen() und getAnzahlKinder() sowie die Operation verheiratet() zu finden. Nun folgt das Erzeugen von vier Objekten vom Typ Person – die gesamte Familie. Zuerst wird ein Objekt vom Typ Person erzeugt, das danach über den Bezeichner papa zur Verfügung steht. Hauptsächlich von Interesse sind die Zeilen 69 bis 76. Hier wird das Attribut kinder initialisiert. Es ist vom Typ Person und kann mehrfach vorkommen. Im Listing sehen Sie, dass es aus zwei Elementen besteht: 69 70 71 72 73 74 75 76
Das folgende Objekt vom Typ Person unterscheidet sich strukturell nicht von diesem Objekt, nur unterscheidet sich der Wert der Eigenschaft name. Von der Zeile 99 bis 112 wird ein weiteres Objekt vom Typ Person erzeugt, das ein Kind repräsentieren soll. Hier ist wieder besonders von Bedeutung, dass das Attribut eltern aus mehreren Person bestehen kann: 104 105 106 107 108 109 110 111
Das Erzeugen des nächsten Objektes unterscheidet sich strukturell wieder nicht vom Erzeugen des dritten Objektes. Der eigentliche Programmablauf, in dem mit den Eigenschaften und Methoden der Objekte agiert wird, besteht aus dem Aufruf verschiedener Methoden der erzeugten Objekte sowie der Ausgabe verschiedener Werte von einigen Eigenschaften. Beachten Sie das Zusammensetzen der Ausgabe-Strings mit concat(). Sie könnten hier in JavaFX auch einen einzelnen String verwenden und darin Objektliterale auswerten.
180
OOP in JavaFX Script
4.8 Vererbung in JavaFX Die Verwendung von Superklassen über den Mechanismus der Vererbung in JavaFX ist im Prinzip ganz einfach127. Optional können Sie in JavaFX wie in Java bei der Deklaration einer Klasse dem Bezeichner der Klasse das Schlüsselwort extends folgen lassen, wenn Sie explizit eine oder mehrere128 Superklassen angeben wollen. Wenn Sie mehrere Superklassen angeben wollen, notieren Sie eine kommatagetrennte Liste mit den Namen der Superklassen. Das nachfolgende Beispiel zeigt die Verwendung von Vererbungsbeziehungen inklusive der Mehrfachvererbung (vererbung): 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
import java.lang.*; // Anlegen von Variablen für die zwei Personen vom Typ Eltern var mama; var papa; // Erste Superklasse Wohnung – die Eigenschaften ort und plz werden // zur Verfügung gestellt class Wohnung { attribute ort: String; attribute plz: Number; } // Superklasse aller Personen – die Eigenschaft name wird // zur Verfügung gestellt class Person { attribute name: String; } // Subklasse Kinder ist abgeleitet von 2 Superklassen und // ergänzt die Attribute alter und eltern (ein Datenfeld). // Das Attribut eltern hat eine bidirektionale Beziehung zu // dem Attribut kinder in der Klasse Eltern class Kinder extends Person, Wohnung { attribute alter: Number; attribute eltern: Eltern* inverse Eltern.kinder; } // Subklasse Eltern ist abgeleitet von 2 Superklassen und // ergänzt das Attribut kinder (ein Datenfeld). // Das Attribut kinder hat eine bidirektionale Beziehung zu // dem Attribut eltern in der Klasse Kinder class Eltern extends Person, Wohnung {
127 Sie müssen nur den Überblick behalten. 128 Um es noch einmal zu betonen – im Gegensatz zu Java unterstützt JavaFX Mehrfachvererbung.
attribute kinder: Kinder* inverse Kinder.eltern; } // Erstes Objekt vom Typ Kinder – alter und eltern sind spezifisch // Auch die vererbten Eigenschaften name und ort, plz // sind verfügbar var sohn1 = Kinder { name: "Felix" alter: 7 ort: "Eppstein" plz : 65817 eltern: [papa, mama] }; // Zweites Objekt vom Typ Kinder var sohn2 = Kinder { name: "Florian" alter: 7 ort: "Eppstein" plz : 65817 eltern: [papa, mama] }; // Erstes Objekt vom Typ Eltern – spezifisch ist die Eigenschaft kinder // Auch die vererbten Eigenschaften name und ort, plz // sind verfügbar papa = Eltern { name: "Ralph" ort: "Eppstein" plz : 65817 kinder:[sohn1, sohn2] }; // Zweites Objekt vom Typ Eltern mama = Eltern { name: "Andrea" ort: "Eppstein" plz : 65817 kinder:[sohn1, sohn2] }; // Zugriff auf die Eigenschaft name des Objekts papa // über das Objekt mama, dessen Eigenschaft kinder[0] und von da // über die Eigenschaft eltern[0] System.out.println(mama.kinder[0].eltern[0].name); // Zugriff auf die analoge Eigenschaft über ein Objekt vom Typ // Kinder und dessen Attribut eltern System.out.println(sohn1.eltern[0].name);
Listing 4.21: Einsatz von Vererbung
182
OOP in JavaFX Script
In dem Beispiel werden zuerst in Zeile 4 und 5 zwei Variablen vom Typ Eltern angelegt (var mama; und var papa;). Diese werden aber erst in der späteren Folge des Skripts auf Objekte vom Typ Eltern verweisen (also konkrete Werte enthalten). Diese Deklaration ohne Initialisierung vor der Verwendung in einer deklarativen Objekterzeugung eines Objekts vom Typ Kinder ist leider notwendig, da es im Gegensatz zu Java und den meisten anderen Situationen in JavaFX bei diesem Quellcode an einer Stelle auf die Reihenfolge der Deklarationen ankommt! Die beiden Variablen mama und papa werden in Zeile 45 und 54 verwendet, um bei der Erzeugung eines Objekts vom Typ Kinder auf Objekte vom Typ Eltern zu referenzieren. Ein Objekt vom Typ Eltern wiederum hat eine Eigenschaft, die auf ein Objekt vom Typ Kinder verweist. Wir haben also in beiden Klassen eine bidirektionale Beziehung auf die jeweils andere Klasse. Das Problem ist nun, dass auch eine Umsortierung der folgenden Quelltextstrukturen maximal dazu führt, dass beim Erzeugen eines Objekts vom Typ Eltern Probleme mit den Objekten sohn1 und sohn2 auftreten würden129. Ich hatte bereits angedeutet, dass man mit bidirektionalen Abhängigkeiten recht diffizile Beziehungen aufbauen kann, die zu gewissen Schwierigkeiten führen können. Die möchte ich mit diesem Beispiel noch einmal verdeutlichen – und auch eine Lösung für einige Situationen, die Sie hier vorliegen haben. In unserem Fall haben wir schlicht und einfach das Problem, ob zuerst das Ei oder die Henne da war. In den Zeilen 9 bis 12 wird nun eine einfache Klasse Wohnung deklariert. Ohne die Angabe einer Superklasse. Darüber stehen einfach nur die Attribute ort und plz zu Verfügung. Die Klasse wird als eine der Superklassen in dem Beispiel verwendet werden. Die Klasse Person wird von Zeile 16 bis 18 deklariert und stellt dieses Mal nur ein Attribut name zur Verfügung. Auch diese Klasse soll in diesem Beispiel nur als Superklasse zum Einsatz kommen. In den Zeilen 24 bis 27 wird die Klasse Kinder deklariert. Diese ist die Subklasse von den zwei Superklassen Eltern und Wohnung. In der Klasse werden die Attribute alter und eltern (ein Datenfeld) ergänzt. Das Attribut eltern besitzt eine bidirektionale Beziehung zu dem Attribut kinder in der Klasse Eltern. Die Deklaration der Klasse Eltern sehen Sie in den Zeilen 33 bis 35. Auch die Klasse ist abgeleitet von unseren beiden Superklassen. Sie ergänzt die vererbten Attribute um das Attribut kinder (ein Datenfeld). Das Attribut kinder hat eine bidirektionale Beziehung zu dem Attribut eltern in der Klasse Kinder. In den folgenden Zeilen werden zwar Objekte vom Typ Kinder und zwei Objekte vom Typ Eltern erzeugt. Dabei können natürlich auch die vererbten Attribute verwendet werden. 129 Das können Sie gerne ausprobieren.
183
Kapitel 4
4.9 Ereignisbehandlung, action und die Technik der Trigger Verschiedene Ereignisse im Lauf eines Programms machen bestimmte Reaktionen notwendig. In der Oberflächenprogrammierung umfasst dies zum Beispiel die Reaktion auf Benutzeraktionen. Die Reaktionsmöglichkeit auf bestimmte Ereignisse ist sogar ein ganz zentraler Aspekt in einer Benutzerschnittstelle. Wenn ein Anwender etwa auf eine Schaltfläche klickt, muss im Programm hinterlegt sein, was daraufhin passieren soll. Wir haben das Attribut action bei verschiedenen GUI-Applikationen in JavaFX ja schon gesehen.
4.9.1 Der allgemeine Mechanismus zur Behandlung von Ereignissen Der allgemeine Mechanismus zur Behandlung dieser Ereignisse nennt sich Ereignisbehandlung oder Eventhandling. Java bietet zwei verschiedene Modelle, wie auf Ereignisse zu reagieren ist. Da gibt es einmal das Eventhandling, wie es in Java vor der Version 1.1 realisiert war. Das nachfolgende Eventhandling 1.1 ist in allen Folgeversionen aktuell. Das Konzept der Reaktion beruht in beiden Fällen auf Mitteilungsobjekten, die vom Laufzeitsystem automatisch bei Bedarf aus Ereignisklassen erstellt werden. Die Ereignisklassen sind vollständig gekapselt und lassen damit keine unnötigen Informationen nach außen durch. Wenn Ereignisse entstehen, müssen diese aber auch irgendwie ausgewertet werden. Es sind reine Mitteilungsobjekte, die erst mal nur da sind und nach einer Behandlung durch einen entsprechend aufgebauten Mechanismus eine Reaktion des Programms bewirken können. Das Ereignisobjekt selbst ist noch keine Reaktion des Programms. Es muss zu einem Auswertungsobjekt transportiert werden. Dies erfolgt über so genannte Delegates und funktioniert schematisch wie folgt: Ein Ereignis tritt bei einem Quellobjekt (dem so genannten Event Source) auf. Das entstandene Ereignisobjekt wird an ein Zuhörerobjekt (einen so genannten Event Listener oder kurz Listener) weitergeleitet, das für ein bestimmtes Quellobjekt registriert ist. Erst der Event-Listener entscheidet über die konkrete Ereignisbehandlung und löst die Reaktion auch aus. Beim Eventhandling in Java wird also ein spezieller Objekttyp benötigt – ein ListenerObjekt, das einem Ereignisprozess eindeutig zugeordnet ist.
184
OOP in JavaFX Script
> >
>
HINWEIS
In JavaFX gibt es zur Reaktion auf Ereignisse in einer grafischen Oberfläche wie in Java nun EventListener als auch so genannte Eventhandler, die aus dem Konzept von Web-Applikationen stammen und sowohl in HTML als auch JavaScript vorkommen. Und sogar die Namen sind denen in JavaScript ähnlich oder gar damit identisch. Ein Eventhandler-Attribut in JavaFX beginnt mit der Silbe on, gefolgt von einer sprechenden Beschreibung des Ereignisses, bei dem es ausgelöst wird.
4.9.2 Die deklarative Reaktion auf ein Standardereignis Das gesamte Verfahren in Java zur Reaktion auf Ereignisse ist logisch und effektiv, aber sehr mächtig und damit nicht ganz trivial. In JavaFX wurde deshalb neben der deklarativen Erzeugung von Objekten mit dem action-Attribut für viele Klassen einer GUI auch eine neue Struktur eingeführt, um mit einem eigenen Mechanismus die Reaktion auf eine bestimmte Art an Ereignissen zu vereinfachen. Über die Schnittstelle javafx.ui.ActionWidget bekommen GUI-Komponenten in JavaFX das Attribut action zur Verfügung gestellt, um eine Operation oder Funktion als Reaktion auf ein Standardereignis130 einer Komponente aufrufen zu können131. Deren Implementierung wird dem Attribut einfach deklarativ als Wert zugeordnet.
4.9.3 Die Deklaration von Trigger Bei Java-Klassen verwenden Sie nun in der Regel – wie schon mehrfach in dem Kapitel angedeutet – keine Konstruktoren in dem Sinn, wie sie in Java vorkommen. Ebenso gibt es für JavaFX-Attribute keine so genannten Setter132, wie sie in Java Bean-Properties zwingend und in gut designten Java-Klassen allgemein empfohlen sind. Stattdessen verwenden JavaFX so genannte Trigger (Auslöser), die SQL-angelehnt sind und eine Behandlung von Ereignissen gestatten, die sich auf Grund von Modifikationen von Daten ergeben. Trigger werden in JavaFX mit dem Schlüsselwort trigger eingeleitet. Dabei enthält ein Trigger einen Kopfbereich (Header) und einen Körper (Body). Der Kopfbereich spezifiziert den Typ des Ereignisses, auf den der Trigger reagieren soll.
130 Bei vielen Komponenten ist so ein Standardereignis der Klick eines Anwenders. Beispielsweise bei einer Schaltfläche, einem Radiobutton oder einem Menüeintrag. 131 Wir haben diese Möglichkeit schon in einigen Beispielen demonstriert, kommen aber darauf vor allen Dingen im folgenden Kapitel 5 bei der Besprechung von grafischen Oberflächen mit Swing zu sprechen. 132 Das sind Methoden zum Setzen von Werten eines Attributs. Sie können dort vor oder nach einer Wertänderung eines Attributs umfangreiche Programmlogik ausführen.
185
Kapitel 4
Der Körper des Triggers ist eine Prozedur, die immer dann ausgeführt wird, wenn das spezifizierte Ereignis auftritt. Innerhalb des Körpers können Sie jede Art von Anweisung notieren, die in einer Operation stehen kann. Trigger verhalten sich also wie Methoden (Funktionen/Operationen), in denen das Kontextobjekt über das Schlüsselwort this zugänglich ist.
4.9.4 Trigger beim Erstellen eines Objekts auslösen Sie können eine Aktion im Kontext eines neu erstellten Objekts ausführen, indem Sie einen Trigger mit der Syntax trigger on new wie folgt erzeugen (trigger1): 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17
import java.lang.System; // Eine einfache Klassendeklaration class X { attribute nums: Number*; } // Definition einers Triggers, der beim Erzeugen // eines Objekts vom Typ X ausgelöst wird trigger on new X { insert [3, 4] into this.nums; } // Neues Objekt vom Typ X // Der Trigger wird ausgelöst var x = new X(); System.out.println(x.nums == [3,4]); // Ausgabe true
Listing 4.22: Die Verwendung eines Triggers
Das Beispiel definiert einen Trigger, der einfach ausgeführt wird, wenn ein neues Objekt der Klasse X erstellt wird. In diesem Fall wird eine Initialisierung der Werte des Attributs nums vorgenommen.
4.9.5 Trigger beim Einfügen von Elementen auslösen Sie können zu jedem Zeitpunkt eine Aktion ausführen, zu dem ein Element in ein Attribut mit mehrfacher Kardinalität eingefügt wird (mit dem insert-Operator). Dazu müssen Sie einen Trigger mit der Syntax trigger on insert wie folgt spezifizieren (trigger2): 01 import java.lang.System; 02 03 class X { 04 attribute nums: Number*;
} trigger on insert num into X.nums { System.out.println( "Gerade wurde {num} in X.nums an Position {indexof num} eingefuegt."); } var x = new X(); insert 12 into x.nums; insert 13 into x.nums;
Listing 4.23: Auslösen eines Triggers beim Einfügen
In diesem Beispiel ist num der Bezeichner einer Variablen, die eine Referenz auf das eingefügte Element als Inhalt hat. Der Kontextindex der Variablen (dieser wird von dem Operator indexof zurückgegeben) korrespondiert mit dem Einfügepunkt.
4.9.6 Trigger beim Löschen von Elementen auslösen Sie können zu jedem Zeitpunkt eine Aktion ausführen, zu dem ein Element aus einem Attribut mit mehrfacher Kardinalität gelöscht wird (mit dem delete-Operator). Dazu müssen Sie einen Trigger mit der Syntax trigger on delete wie folgt spezifizieren (trigger3): 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17
import java.lang.System; class X { attribute nums: Number*; } trigger on delete num from X.nums { System.out.println( "Gerade wurde {num} in X.nums an Position {indexof num} geloescht"); } var x = X { nums: [12, 13] }; delete x.nums[1]; delete x.nums[0];
Listing 4.24: Auslösen eines Triggers beim Löschen
In diesem Beispiel ist num der Bezeichner einer Variablen, die eine Referenz auf das gelöschte Element als Inhalt hat. Der Kontextindex der Variablen (dieser wird von dem Operator indexof zurückgegeben) korrespondiert mit dem Löschpunkt.
187
Kapitel 4
4.9.7 Trigger beim Ersetzen von Werten auslösen Sie können zu jedem Zeitpunkt eine Aktion ausführen, zu dem ein Element aus einem Attribut mit mehrfacher Kardinalität ersetzt wird. Dazu müssen Sie einen Trigger wie folgt spezifizieren (trigger4): 01 import java.lang.System; 02 03 class X { 04 attribute nums: Number*; 05 attribute num: Number?; 06 } 07 08 trigger on X.nums[oldValue] = newValue { 09 System.out.println("Gerade wurde {oldValue} durch {newValue} an der 10 Position {indexof newValue} in X.nums ersetzt"); 11 } 12 13 trigger on X.num[oldValue] = newValue { 14 System.out.println("X.num: gerade wurde {oldValue} durch {newValue} ersetzt"); 15 } 16 17 var x = X { 18 nums: [12, 13] 19 num: 100 20 }; 21 22 // Verschiedene Ersetzungen 23 x.nums[1] = 5; 24 x.num = 3; 25 x.num = null; Listing 4.25: Auslösen eines Triggers beim Ersetzen
In dem Beispiel sind oldValue und newValue die Namen der Variablen, die Referenzen auf die Werte beinhalten, die ersetzt werden. Der Kontextindex den Variablen (dieser wird von dem Operator indexof zurückgegeben) korrespondiert mit der ordinalen Position des ersetzten Elements.
> >
>
HINWEIS
Zu einem weiteren umfangreicheren Beispiel mit Triggern siehe auch Seite 192.
188
OOP in JavaFX Script
4.10 Inkrementelle und »Lazy« Evaluierung In JavaFX können Sie eine so genannte inkrementelle und/oder lazy (faule) Evaluierung von Ausdrückung vornehmen. Inkrementelle Evaluierung ist eines der zentralen Features von JavaFX zur deklarativen Erstellung von komplexen dynamischen grafischen Benutzeroberflächen. Das Feature der lazy-Evaluierung wird in JavaFX beispielsweise benötigt, um mit rekursiven Datenstrukturen wie Bäumen und Graphen umgehen zu können.
4.10.1 Inkrementelle Evaluierung Schauen wir uns zunächst die rein inkrementelle Evaluierung von Ausdrückung an. Dazu wird der bind-Operator bei einer Initialisierung als Wert eines Attributs angegeben. Attribute, die mit dem bind-Operator initialisiert werden, sind so ungefähr wie Zellen in einer Tabelle einer Tabellenkalkulation zu sehen, die Formeln anstelle von Werten enthalten. Diese Formeln beziehen sich auf andere Zellen (der rechte Operand von bind). Wenn sich während der Lebenszeit eines Objekts, das das Attribut enthält, bei dem referenzierten Attribut auf irgendeine Weise der Wert ändert, werden sich alle anderen daran gebundenen Attribute in der Weise ändern, wie die Bindungsvorschrift (die Formel) das verlangt. Und das ohne Verzögerung und ohne, dass die Aktualisierung noch manuell ausgelöst werden muss. Das nachfolgende Beispiel sollte das Verfahren deutlich machen (inkrementelleevaluierung): 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21
import java.lang.System; // Klasse mit drei Attributen class X { attribute a: Number; attribute b: Number; attribute c: Number; } // Attribut x wird initialisiert attribute X.a = 10; // Attribut b wird an das Attribut // a mit einer Formel gebunden // der Wert von b ist immer um 10 höher als von a attribute X.b = bind a + 10; // Attribut c wird an das Attribut // b mit einer Formel gebunden // der Wert von c ist immer um 5 höher als von b attribute X.c = bind b + 5;
// Objekt der Klasse X wird erzeugt var x = new X(); // Ausgabe der Werte aller drei Attribute nach // der Initialisierung System.out.println( "Werte aller drei Attribute nach der Initialisierung:"); System.out.println("x.a: {x.a}"); // Ausgabe von 10 System.out.println("x.b: {x.b}"); // Ausgabe von 20 System.out.println("x.c: {x.c}"); // Ausgabe von 25 // Änderung von a x.a = 5; System.out.println( "Werte aller drei Attribute nach der Zuweisung System.out.println("x.a: {x.a}"); // Ausgabe von System.out.println("x.b: {x.b}"); // Ausgabe von System.out.println("x.c: {x.c}"); // Ausgabe von
ueber x.a:"); 5 15 20
// Änderung von c x.c = 12; System.out.println( "Werte aller drei Attribute nach der Zuweisung System.out.println("x.a: {x.a}"); // Ausgabe von System.out.println("x.b: {x.b}"); // Ausgabe von System.out.println("x.c: {x.c}"); // Ausgabe von
ueber x.c:"); -3 7 12
Listing 4.26: Verwendung des Operators bind
Von Zeile 4 bis 8 wird eine Klasse X mit drei numerischen Attributen a, b und c deklariert. In Zeile 11 wird das Attribut a initialisiert: attribute X.a = 10;
In Zeile 16 wird das Attribut b initialisiert und dabei mit dem Operator bind an das Attribut a mit einer Formel gebunden. Die Formel besagt, dass der Wert von b immer um 10 höher als der Wert von a ist: attribute X.b = bind a + 10;
In Zeile 21 wird nun zusätzlich das Attribut c an das Attribut b (das wie gesagt von a abhängt) mit einer anderen Formel gebunden. Der Wert von c ist immer um 5 höher als der Wert von b: attribute X.c = bind b + 5;
In Zeile 24 wird ein Objekt der Klasse X erzeugt: var x = new X();
190
OOP in JavaFX Script
Die folgenden Zeilen zeigen in der Ausgabe die Werte aller drei Attribute nach der Initialisierung. Die Ausgabe der Zeile 31 zeigt, dass der Wert von b wie gefordert um 10 höher ist als der Wert von a und c wiederum um den Wert 5 gegenüber b erhöht ist. Die Änderung des Attributs a erfolgt nun in Zeile 35: x.a = 5;
Die nachfolgenden Ausgaben beweisen, dass auch die anderen Attribute ihre Werte entsprechend geändert haben. Aber auch, wenn die Änderung über das Attribut c erfolgt (Zeile 43 – x.c = 12;), sind die Werte der anderen beiden Attribute angepasst worden. Das ist die Ausgabe des Beispiels: Werte aller drei Attribute nach der Initialisierung: x.a: 10 x.b: 20.0 x.c: 25.0 Werte aller drei Attribute nach der Zuweisung ueber x.a: x.a: 5 x.b: 15.0 x.c: 20.0 Werte aller drei Attribute nach der Zuweisung ueber x.c: x.a: -3.0 x.b: 7.0 x.c: 12
4.10.2 Die lazy-Evaluierung Schauen wir uns nun an, wie sich eine lazy-Bindung verhält. Vereinfacht gesagt geht es darum, dass eine Evaluierung eines Ausdrucks nur dann erfolgt, wenn es wirklich notwendig ist133.
133 Man könnte es sich auch so vorstellen: Kinder haben von der Mutter den Befehl bekommen, ihr Kinderzimmer aufzuräumen. Sie ziehen ab und behaupten dann, dass sie es gemacht haben. Tatsächlich haben sie aber nicht aufgeräumt und erledigen das erst dann, wenn die Mutter bei einer Nachkontrolle im Kinderzimmer steht und tobt. Irgendwie habe ich so eine lazy-Situation fast täglich auszuhalten ;-).
import java.lang.System; // Klassendeklaration mit drei Attributen class X { attribute a: Number; attribute b: Number; attribute c: Number; } // Trigger, um auf die Änderung eines Wert // des Attributs b zu reagieren trigger on X.b = newValue { System.out.println( "Trigger fuer eine Wertaenderung wurde ausgeloest."); System.out.println( "Wertaenderung von X.b! X.b hat nun den Wert {newValue}"); } // Trigger, um auf die Änderung eines Werts // des Attributs c zu reagieren trigger on X.c = newValue { System.out.println( "Trigger fuer eine Wertaenderung wurde ausgeloest."); System.out.println( "Wertaenderung von X.c! X.c hat nun den Wert {newValue}"); } // Erzeugen von Objekt x1 mit Initialisierung durch Literale var x1 = X { // Initialisierung der Attribute von x1 a: 1 // x1.a hat nun den Wert 1 b: 2 // x1.b hat nun den Wert 2 c: 3 // x1.c hat nun den Wert 3 }; // Erzeugen von Objekt x2 mit Initialisierung durch die Werte der // Attribute in dem Objekt x1 var x2 = X { // a in x2 bekommt den Wert von x1.a - nichtinkrementell a:x1.a // b in x2 bekommt Wert von x1.b – inkrementelle Bindung // x2.b hat dann den Wert 2 b:bind x1.b // lazy und inkrementelle Bindung von c in x2 an c in x1 // x2.c hat noch keinen Wert
c:bind lazy x1.c }; System.out.println("Wert von x2.a: {x2.a}"); // Ausgabe von 1 System.out.println("Wert von x2.b: {x2.b}"); // Ausgabe von 2 // x2.c bekommt erst durch den Zugriff den Wert 3 - dann Ausgabe von 3 System.out.println("Wert von x2.c: {x2.c}"); x1.a = 5; // x2.a ändert sich nicht - keine Bindung x1.b = 5; // x2.b hat nun den Wert 5, da inkrementell an x1.b gebunden x1.c = 5; // x2.c hat den Wert 5 noch nicht, da lazy gebunden System.out.println("Wert von x2.a: {x2.a}"); // Ausgabe von 1 System.out.println("Wert von x2.b: {x2.b}"); // Ausgabe von 5 // x2.c bekommt erst durch den Zugriff den Wert 3 - dann Ausgabe von 5 System.out.println("Wert von x2.c: {x2.c}");
Listing 4.27: Die Verwendung einer lazy-Bindung
In dem Beispiel haben wir wieder die gleiche Klassendefinition, wie Sie sie im vorherigen Beispiel gesehen haben (Zeile 4 bis 8). Nur initialisieren wir hier die Attribute nicht auf die gleiche Weise wie im Beispiel zuvor. In dieser Variante arbeiten wir mit zwei Objekten und initialisieren die Attribute beim jeweiligen Erzeugen eines Objekts. Die Trigger in dem Beispiel reagieren einfach auf jede Wertänderung der Attribute b und c. Das soll uns helfen zu sehen, wann sich tatsächlich die Werte der Attribute ändern. Das Erzeugen des Objekts x1 (Zeile 29 bis 34) ist »harmlos«. Mit einer deklarativen Syntax bekommen die Attribute einfach Literale als Werte zugewiesen. 29 var x1 = X { 30 // Initialisierung der Attribute von x1 31 a: 1 // x1.a hat nun den Wert 1 32 b: 2 // x1.b hat nun den Wert 2 33 c: 3 // x1.c hat nun den Wert 3 34 }; Listing 4.28: Deklaratives Erzeugen des Objekts x1 und Initialisierung der Attribute mit Literalen
Die erneut deklarativ notierte Erzeugung des Objekts x2 ist interessanter (Zeile 38 bis 49). Die Initialisierung erfolgt durch die Werte der Attribute in dem Objekt x1: 38 var x2 = X { 39 // a in x2 bekommt den Wert von x1.a - nichtinkrementell 40 a:x1.a 41 42 // b in x2 bekommt Wert von x1.b – inkrementelle Bindung 43 // x2.b hat dann den Wert 2
193
Kapitel 4 44 b:bind x1.b 45 46 // lazy und inkrementelle Bindung von c in x2 an c in x1 47 // x2.c hat noch keinen Wert 48 c:bind lazy x1.c 49 }; Listing 4.29: Deklaratives Erzeugen des Objekts x2 und Initialisierung der Attribute durch die Attribute von x1
Wir schaffen also eine Verbindung zwischen den Attributen im Objekt x1 und den Attributen in dem neuen Objekt. Das Attribut a in x2 bekommt einfach den Wert von x1.a in Zeile 40 zugewiesen (a:x1.a). Das ist nichtinkrementell. Mit anderen Worten: Das Attribut in dem Objekt x2 wird zwar mit dem Wert aus dem Objekt x1 initialisiert, aber dann gibt es keine Verbindung zwischen diesen beiden Attributen mehr. In dem Beispiel werden jedoch die Attribute b und c des Objekts x2 wieder an die jeweiligen Attribute b (Zeile 44) und c (Zeile 48) des Objekts x1 gebunden. Das bedeutet wie im vorherigen Beispiel, dass jede Änderung von b oder c über das Objekt x1 die korrespondierenden Attributwerte x2 aktualisiert und umgekehrt. Das war im Grunde auch schon bei der reinen Verwendung von bind so. Es gibt jedoch bei der Bindung des Attributes c über lazy (Zeile 48: c:bind lazy x1.c) einen gravierenden Unterschied zu dem Fall, wenn auf dieses Schlüsselwort verzichtet wird. Es dreht sich darum, wann bei einer neuen Wertzuweisung die Aktualisierung in dem verbundenen Attribut stattfindet. Im Fall einer Bindung nur über bind wird der ehemalige Wert bei einer Änderung sofort aktualisiert, wenn eine neue Wertzuweisung über eine der verbundenen Eigenschaften erfolgt. Im Fall der zusätzlich als lazy gekennzeichneten Bindung wird diese nicht evaluiert, bis zu dem Zeitpunkt, an dem das erste Mal auf dessen Wert zugegriffen wird. Das System verhält sich also »faul«, weil es eine Wertveränderung nur dann durchführt, wenn tatsächlich auf das Attribut zugegriffen wird134.
134 Vorher kann man sich ja die Arbeit sparen. Oder wieder aus dem Leben gegriffen – sollte die Mutter gar nicht ins Zimmer kommen, wozu wäre der ganze Aufwand mit dem unnötigen Ausfäumen notwendig gewesen ;-)?
194
OOP in JavaFX Script
Betrachten wir die Ausgabe des Beispiels, die ausnahmsweise zur Verdeutlichung nummeriert ist (das sehen Sie natürlich nicht, wenn Sie das Beispiel laufen lassen): 01 Trigger fuer eine Wertaenderung wurde ausgeloest. 02 Wertaenderung von X.b! X.b hat nun den Wert 2 03 Trigger fuer eine Wertaenderung wurde ausgeloest. 04 Wertaenderung von X.c! X.c hat nun den Wert 3 05 Trigger fuer eine Wertaenderung wurde ausgeloest. 06 Wertaenderung von X.b! X.b hat nun den Wert 2 07 Wert von x2.a: 1 08 Wert von x2.b: 2 09 Trigger fuer eine Wertaenderung wurde ausgeloest. 10 Wertaenderung von X.c! X.c hat nun den Wert 3 11 Wert von x2.c: 3 12 Trigger fuer eine Wertaenderung wurde ausgeloest. 13 Wertaenderung von X.b! X.b hat nun den Wert 5 14 Trigger fuer eine Wertaenderung wurde ausgeloest. 15 Wertaenderung von X.b! X.b hat nun den Wert 5 16 Trigger fuer eine Wertaenderung wurde ausgeloest. 17 Wertaenderung von X.c! X.c hat nun den Wert 5 18 Trigger fuer eine Wertaenderung wurde ausgeloest. 19 Wertaenderung von X.c! X.c hat nun den Wert 5 20 Wert von x2.a: 1 21 Wert von x2.b: 5 22 Wert von x2.c: 5 Ein entscheidender Punkt ist schon in den Zeilen 5 und 6 zu sehen. Der Trigger für die Wertänderung des Attributs b wurde ausgelöst, der Trigger für das Attribut c aber nicht. Wir haben nun den Zeitpunkt, an dem im Quelltext in Zeile 40 a:x1.a, in Zeile 44 b:bind x1.b und in Zeile 48 c:bind lazy x1.c ausgeführt wurde. Da der Trigger für c aber nicht ausgelöst wurde, beweist dies, dass sich der Wert von c bis zu dem Zeitpunkt nicht geändert hat. Von dem Attribut b aber schon.
195
Kapitel 4
Erst in Zeile 9 der Ausgabe wird der Trigger für c als ausgelöst kenntlich. Das entspricht im Quelltext der Anweisung System.out.println("Wert von x2.c: {x2.c}"); in Zeile 54, in der tatsächlich das Attribut verwendet wird. Das ist der Zeitpunkt der Wertänderung. Die nachfolgenden Ausgaben zeigen den Vorgang dann noch einmal.
> >
>
HINWEIS
Der Körper einer Funktion wird immer inkrementell ausgewertet. Ohne die explizite Notation von bind. Im Körper einer Operation ist dies nicht der Fall. Im Gegensatz zu einer Funktion werden Änderungen an lokalen Variablen in einer Operation keine inkrementelle Evaluierung auslösen. Inkrementelle Evaluierung im Körper einer Operation wird also nicht unterstützt, es sei denn, es wird explizit mit bind gearbeitet. Dessen ungeachtet gilt, dass ein Aufruf einer Operation (oder einer Java-Methode) aus einem inkrementell ausgewerteten Kontext selbst wieder inkrementell ausgewertet wird. Das bedeutet, wenn sich der Wert von einem der Argumente des Aufrufs ändert, wird ein neuer Aufruf der Operation oder Methode durchgeführt und ein neuer Wert zurückgegeben. Im Gegensatz dazu werden Funktionen nur einmal aufgerufen und das Resultat der Evaluierung wird in den Auswertungsbaum des Aufrufers eingebunden.
196
5
Swing-Applikationen mit JavaFX Script
Sie haben bisher in dem Buch außer einigen einfachen Beispielen noch nicht viel von den optischen Möglichkeiten von JavaFX zur Erstellung einer grafischen Benutzerschnittstelle gesehen. Um eine Sprache zu lernen, muss man sich135 grundsätzlich zuerst einmal mit der Syntax und den Konzepten der Technologie auseinander setzen. Und das bedeutet zwangsläufig eine Beschäftigung mit vielen recht trockenen Strukturen. Da führt kein Weg dran vorbei. Das ist aus didaktischen Gründen sinnvoll, um nicht mit Nebensächlichkeiten wie dem Aufbau eines Fensters und der Ausgabe dort die Beispiele zu überfrachten. Nun aber wird es bunt :-)! Oder anders gesagt – Sie sehen nun, wie man mit JavaFX Script grafische Benutzeroberflächen erzeugt. Und natürlich sind moderne Anwendungen fast immer mit einer grafischen Oberfläche versehen. Wir haben nun das notwendige Syntaxrüstzeug sowie die Grundlagen des Konzepts von JavaFX vorbereitet und wollen in diesem umfangreichsten Kapitel des Buchs also GUI-Anwendungen (Grapic User Interface) und deren Aufbau behandeln. Sie werden sehen, dass dies mit den gründlichen Vorbereitungen der bisherigen Kapitel fast zum Kinderspiel wird136.
135 Leider ;-). 136 Was aber nicht bedeutet, dass man nicht dennoch hochkomplexe Syntaxstrukturen entwickeln kann.
Kapitel 5
5.1 Was ist Swing? Wenn Sie grafische Benutzeroberflächen in Java erstellen wollen, fallen Ihnen viele notwendige Aktionen durch die Verfügbarkeit mächtiger Java-Objekte und das Vererbungsprinzip nahezu in den Schoß. Grundlage jeder GUI unter Java und damit auch JavaFX ist das AWT (Abstract Windowing Toolkit137) und die darauf aufbauende Erweiterung Swing.
5.1.1 Das AWT und Swing Anwenderkommunikation erfolgt in allen modernen Programmen über grafische Benutzerschnittstellen aus Schaltflächen, Menüs, Eingabefeldern, Navigationsbäumen etc. Es gibt mittlerweile kaum noch ein Betriebssystem beziehungsweise Programm, das ohne solch ein GUI auskommt. Und natürlich müssen sich Applikationen in eine Betriebssystemumgebung einfügen. Sie müssen die Bedienelemente verwenden, die ein Anwender von anderen Programmen gewohnt ist. In Java sollte nun ein GUI aber plattformunabhängig (!) genutzt werden können, da diese Plattformunabhängigkeit ein zentrales Feature der gesamten Java-Philosophie ist. Damit war von Sun bei der Konzeption eines GUI-Systems ein erhebliches Problem zu lösen. Eine grafische Benutzerschnittstelle kann je nach zugrunde liegendem Betriebssystem ziemlich unterschiedlich aussehen und zu bedienen sein. Auch die konkreten Gegebenheiten einer Plattform bei einem Benutzer wie die Bildschirmauflösung können das Aussehen einer GUI massiv beeinflussen. Wie kann man also ein portierbares und plattformunabhängiges grafisches API entwickeln, das alle Konzepte verschiedener Betriebssysteme sowie unterschiedlicher Gegebenheiten bei einem Anwender berücksichtigt?
Das AWT In der ersten Variante eines Java-Toolkits zur Erstellung einer GUI stellte Sun über Java nur eine Art kleinsten gemeinsamen Nenner aller zu unterstützenden Plattformen bereit. Dieses allgemeingültige API heißt AWT. Das AWT realisiert die Elemente, die auf allen Zielplattformen Sinn machen. Natürlich konnte man sich bei einem solchen Ansatz nicht zu 100 % für ein bestehendes Look and Feel einer einzelnen Plattform wie Windows entscheiden, sondern musste in diversen Situationen eigene Wege gehen, die die besten Ideen aus verschiedenen zugrunde liegenden Plattformen beinhalten.
137 In einigen Quellen auch Abstract Window Toolkit genannt.
198
Swing-Applikationen mit JavaFX Script
Das AWT verwendet nur so genannte Widgets (z. B. Button, Eingabefelder, Menüs etc.)138, die auf allen Plattformen unterstützt werden. Dies bedeutet, dass Komponenten wie Bäume oder Tabellen im AWT nicht vorhanden sind. Ebenso verwendet das AWT so genannte Layoutmanager, um das Aussehen von GUIApplikationen möglichst unabhängig von den Plattformbedingungen und stark automatisiert139 zu verwalten. Im Grunde ist das AWT eine einheitliche objektorientierte Schicht oberhalb von dem jeweiligen nativen Fenstersystem einer Plattform.
Swing Die AWT-Lösung für ein GUI hat Sun nicht nur Lob eingebracht. Im Gegenteil. Nicht nur die eingeschränkte Auswahl der Elemente, sondern auch andere Unzulänglichkeiten wie das unbefriedigende Eventhandling (die Reaktion auf Benutzereingaben) sorgten für Kritik. Auch konnten sich viele Programmierer mit dem automatischen Verwalten der Bestandteile einer Benutzerschnittstelle nicht so recht anfreunden. Und auch die Flexibilität eines Anwenders hat man bei Sun massiv überschätzt. Statt die 95% der Fälle zu sehen, in denen eine AWT-Applikation mit einer nativen Applikation (etwa einer Windows-Applikation) übereinstimmt, hat sich die Masse der Anwender bei einer Java-Applikation auf die 5% Abweichung im »Look and Feel« konzentriert und diese extrem kritisiert. Das AWT wurde zwar in der Version 1.1 weit reichend erweitert und verbessert, aber so richtig glücklich ist niemand mit dem AWT geworden. Sun hat deshalb als Ergänzung mit dem Swing-Konzept quasi eine Ablösung des AWT geschaffen, das aber dennoch über den Mechanismus der Vererbung auf dem AWT aufsetzt. Und manche Elemente aus dem AWT werden auch in Swing unverändert verwendet. Mit der Einführung von Swing einher ging ein neues Eventhandling. Das 1.1-Eventmodell ist zwar im Grunde unabhängig vom AWT und Swing, wird jedoch im Swing-Konzept standardmäßig verwendet. Swing implementiert gegenüber dem AWT einen neuen Satz von GUI-Komponenten mit anpassungsfähigem »Look and Feel«. Swing ist vollständig in Java implementiert und basiert auf dem JFC (Java Foundation Classes). Das Aussehen und die Reaktionen von GUI-Komponenten lassen sich in Swing auf viele Arten anpassen. Und auch die Anzahl der Layoutmanager wurden gegenüber dem AWT erweitert und gestattet dem Programmierer weitergehende Kontrolle über das Aussehen der GUI. 138 Das sind in diesem Fall spezielle Java-Objekte mit einer bestimmten Schnittstelle, wie sie von außen verwendet werden können. 139 Das bedeutet, sowohl die Position von Komponenten als auch die Größe werden nicht explizit angegeben, sondern im Rahmen von sehr flexiblen Regeln automatisch durch die Layoutmanager angepasst.
199
Kapitel 5
5.2 Swing und JavaFX »There’s nothing wrong with Swing. « – so ist der Satz in der offiziellen Dokumentation zur Erstellung von grafischen Oberflächen mit JavaFX zu finden. Sun behauptet ganz ausdrücklich, dass Swing eines der besten Entwicklungs-Toolkits zur Erstellung von grafischen Oberflächen ist. Und es wird ausdrücklich betont, dass JavaFX Swing nicht ersetzen soll. Im Gegenteil – JavaFX Script soll nur die Erstellung von SwingApplikationen erleichtern. Denn in der Tat ist die Erstellung einer Swing-Applikation nicht ganz primitiv. Insbesondere die Ereignisbehandlung und die Erstellung komplexer Widgets haben so ihre Tücken140.
5.2.1 Deklarative Erzeugung von Objekten als Erleichterung Wir haben im letzzen Kapitel ja die deklarative Erzeugung von Objekten in JavaFX kennen gelernt. Der Ansatz von JavaFX ist nun, dass die deklarative Erzeugung von Objekten insbesondere die Erstellung einer grafischen Benutzerschnittstelle erleichtert. Wobei in JavaFX trotzdem die klassische Swing-Programmierung zusätzlich auch unterstützt wird. Schauen wir uns zur Verdeutlichung ein Codefragment aus JavaFX an, das vom Aufbau der Vorgehensweise in Swing entspricht: 01 02 03 04 05 06 07
var win = new Frame(); win.title = "Mein Swing-Fenster"; win.width = 200; var label = new Label(); label.text = "Hallo Welt"; win.content = label; win.visible = true;
Listing 5.1: Ein Ansatz wie in der klassischen Swing-Programmierung
In dem Fragment passiert Folgendes: Zeile 1: Ein Konstruktor der Klasse Frame wird aufgerufen, um ein neues Frame (ein Fenster mit einer grafischen Oberfläche) zu erzeugen. Zeile 2: Dem Attribut title (der Titelzeile des Fensters) des Frames wird ein Wert zugewiesen. Zeile 3: Dem Attribut width (der Breite des Fensters) des Frames wird ein Wert zugewiesen.
140 Vor allen Dingen wenn man dies von Hand macht und keine mächtige IDE (möglichst noch mit einer visuellen Erstellungsebene) verwendet.
200
Swing-Applikationen mit JavaFX Script
Zeile 4: Ein Objekt vom Typ Label (eine Beschriftung) wird mit einem Konstruktor der Klasse erzeugt. Zeile 5. Dem Attribut text des Objekts vom Typ Label (dem Text in dem Label) wird ein Wert zugewiesen. Zeile 6: Dem Attribut content des Frames (dem Inhalt) wird das Objekt vom Typ Label als Wert zugewiesen. Zeile 7: Dem Attribut visible des Frames wird als Wert true zugewiesen und das Frame damit angezeigt. Obwohl dieses einfache Beispiel ziemlich klar und stringent ist, ist die Bedeutung eines Programms in der deklarativen Syntax nach der Einschätzung von Sun dennoch leichter zu begreifen. Die deklarative Programmierung versucht ein Programm aus einem einzelnen Wurzelausdruck zu entwickeln. Greifen wir noch einmal auf das erste Hallo-Welt-Programm aus Kapitel 2 zurück, das eine vollkommen analoge Situation wie die Swing-orientierte Syntax oben beschreibt: 01 import javafx.ui.*; 02 03 Frame { 04 title: "Meine erste JavaFX-Applikation" 05 width: 300 06 height: 100 07 content: Label { 08 text: "Willkommen in der Welt von JavaFX" 00 } 10 visible: true 11 } Listing 5.2: Das erste JavaFX-Programm aus Kapitel 2
Hier ist die Wurzel des gesamten Ausdrucks ein Allokierungsausdruck für ein Objekt in Zeile 3, der die Grundgrafik (oder genauer: ein Frame mit einer grafischen Oberfläche) generiert und für das gesamte Programm steht.
5.2.2 Hinzufügen eines dynamischen Verhaltens – die Model/ View-Version Das Hallo-Welt-Programm zeigt bisher keinerlei dynamisches Verhalten (also Reaktion auf Veränderungen). Weder in der Swing- noch in der deklarativen Variante. Um nun eine grafische Benutzerschnittstelle mit einem dynamischen Verhalten in JavaFX zu erzeugen, erstellen Sie beispielsweise einfach GUI-Komponenten, derer Properties
201
Kapitel 5
(Eigenschaften) von den Attributwerten anderer Objekte abhängen. Dazu kommt der bind-Operator zum Einsatz, den wir im Kapitel 4 ausführlich kennen gelernt haben. Solche verbundenen anderen Objekte können alles sein, was auch immer eine Repräsentation des Status Ihrer Applikation darstellt. Und da die Properties von GUI-Komponenten bei diesem Ansatz immer direkt von relevanten Properties von einer gewissen Anzahl an anderen Objekten abhängen, werden die GUI-Komponenten automatisch deren Änderungen reflektieren, wann immer Sie Modifikationen an einem der anderen Objekte vornehmen.
> >
>
HINWEIS
In diesem Zusammenhang werden GUI-Komponenten typischerweise als »View« und die »anderen« Objekte als das »Model« bezeichnet.
Nachfolgend sehen Sie eine dynamische Model/View-Version des Hallo-Welt-Programms (modelview): 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20
Listing 5.3: Dynamisches Verhalten eines Swing-Frame
In Zeile 1 importieren Sie das JavaFX-Paket zur Unterstützung von grafischen Benutzeroberflächen per Swing. Die Klasse ModelView stellt in Zeile 4 ein einfaches Attribut nunSagSchon vom Typ String zur Verfügung.
202
Swing-Applikationen mit JavaFX Script
Abbildung 5.1: Ein Swing-Frame mit dynamischem Verhalten
In den Zeilen 7 bis 9 wird ein Objekt model vom Typ ModelView erzeugt. In Zeile 8 bekommt das Attribut nunSagSchon einen spezifischen Wert zugewiesen. In den Zeilen 11 bis 20 wird ein Objekt vom Typ javafx.ui.Frame mit dynamischem Verhalten erzeugt. Dabei ist nur die Zeile 17 interessant, denn der Rest unterscheidet sich nicht von dem vorher gezeigten Hallo-Welt-Programm. In Zeile 17 jedoch wird dem Attribut text unter Verwendung des bind-Operators eine Beziehung zum Attribut model.nunSagSchon zugeordnet. Wenn sich nun das Attribut nunSagSchon vom Objekt model verändert wird, ändert sich automatisch die Anzeige in dem Frame.
> >
>
HINWEIS
So eine Attributbeziehung ist vor allen Dingen bei Eingabe-Widgets wie Schaltflächen, Kontrollkästchen und Textfeldern von Bedeutung.
Betrachten wir noch ein weiteres Beispiel, indem die gebundene Beziehung zwischen Attributen deutlicher wird (modelview2): 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17
Wenn Sie das Programm ausführen, sehen Sie in der Titelleiste des Fensters die Angabe haudichraus.blogspot.com.
Abbildung 5.2: Die Titelzeile ist mit einem Text vorbelegt
Für die Vorbelegung sorgt die Zeile 12. Das Attribut title ist an das Attribut model.nunSagSchon gebunden. Nun sehen Sie in den Zeilen 16 bis 18 als Inhalt des Frames ein Textfeld. Dessen Attribut value repräsentiert den Inhalt des Textfeldes. Und dieses Attribut ist ebenfalls an das Attribut model.nunSagSchon gebunden. Wenn Sie nun im Textfeld eine Änderung vornehmen und diese bestätigen, wird unmittelbar die Titelzeile des Fensters verändert.
Abbildung 5.3: Die Titelzeile wurde dynamisch an den Inhalt des Textfeldes angepasst
5.3 Grundlagen zu Komponenten in JavaFX Komponenten sind die Elemente, über die eine Interaktion mit dem Endanwender bei einem GUI konkret realisiert wird. Die GUI-Komponenten in JavaFX beziehungsweise Swing und dem AWT umfassen verschiedene Arten: Frames selbst Rahmen und Layoutmanager Menüs Label Panel zur Gruppierung Textfelder
204
Swing-Applikationen mit JavaFX Script
Schaltflächen ListBoxes SplitPanes CheckBoxes, RadioButtons, RadioButtonMenuItems, ToggleButtons, und ButtonGroups ComboBoxes Bäume Tables TextComponents Spinners und Sliders Sie kennen die meisten Komponenten ziemlich sicher aus den unterschiedlichen Programmen mit grafischen Benutzerschnittstellen. Die Komponenten hier kann man nach ihrer Funktion im Wesentlichen in Komponenten der Benutzeroberfläche (etwa Schaltflächen, Kontrollfelder, ...) und Fensterkomponenten (Frames, Bildlaufleisten, Rahmen, Menüleisten, ...) einteilen. Die Fensterkomponenten trennt man logisch von den Komponenten der Benutzeroberfläche, da sie in der Regel unabhängig von der integrierten Anwendung betätigt werden (beispielsweise löst das Verschieben von Fensterinhalt über Bildlaufleisten oder das Verändern der Größe eines Fensters noch keine Aktion in der Applikation aus).
5.3.1 Widget – die Superklasse der meisten GUI-Komponenten Die meisten Komponenten in JavaFX sind von javafx.ui.Widget abgeleitet und erben von da bereits wesentliche Funktionalitäten. Etwa Attribute zur Ausrichtung in verschiedener Form (z. B. alignmentX, alignmentY oder componentOrientation), zum Setzen von Farben von Hintergrund und der Schrift (z. B. awtBackground, awtForeground, background foreground), zur Schriftart, der -größe und dem -typ (z. B. awtFont, font), zu der Art und dem Aussehen eines Rahmens (border), der Art des Mauszeigers (cursor), dem Aktivierungszustand (enabled), dem Fokus (z. B. focused oder focusable),
205
Kapitel 5
der Größe einer Komponente (z. B. size, height oder width), der Maximal- und Minimalgröße (maximumSize und minimumSize), dem Anzeigen eines Tooltipps (toolTipText) oder der Sichtbarkeit (visible). Dazu kommt noch eine Vielzahl an spezifischen Listenern, mit denen Sie sich aber in JavaFX meist nicht unmittelbar zu beschäftigen brauchen. Diese dienen dazu, auf bestimmte Ereignisse zu reagieren, die von dem Defaultereignis abweichen, das mit dem Attribut action spezifiziert wird. Etwa um auf spezielle Mausaktionen (mouseListener, mouseMotionListener oder mouseWheelListener) oder Tastaturereignisse (keyListener) zu reagieren. Ebenso finden Sie in der Klasse Eventhandler wie onKeyDown und onKeyUp oder onMouseDragged, onMouseEntered, onMouseClicked oder onMouseExited. Die Klasse Widget stellt des Weiteren diverse Methoden zur Verfügung, vor deren direkten Gebrauch Sie aber das Konzept von JavaFX Script bewahren sollte und die wir hier nicht weiter verfolgen werden. 141
> >
>
HINWEIS
Grundsätzlich werden wir in dem Buch nicht alle Komponenten und deren vielfältigen Attribute und Methoden bis ins letzte Detail besprechen (können)141. Das ist aber auch definitiv nicht notwendig. Zum einen ist es heutzutage jedem Computeranwender klar, was eine bestimmte Komponente für eine Funktion und Verhaltensweise hat. Oder muss Ihnen erklärt werden, was man mit einem Button, einem Menü oder einer Bildlaufleiste machen kann? Daraus ergeben sich sehr oft die möglichen Attribute und Methoden einer Komponente fast zwangsläufig. Zum anderen langt es, wenn man einzelne Komponente bestimmter Typen genauer untersucht. Die Komponenten sind so konstruiert, dass man die in einer Komponente realisierten Konzepte leicht auf verwandte Komponenten übertragen kann. In der Regel werden sich die Attribute überall wiederholen, wo eine identische Funktionalität umgesetzt werden soll. Und nicht zuletzt steht – wie in Kapitel 2 schon erwähnt – steht eine hervorragende Dokumentation des JavaFX Script APIs zum Zeitpunkt der Bucherstellung unter dem URL https://openjfx. dev.java.net/nonav/api/index.html zur Verfügung. Hier finden Sie die Beschreibung sämtlicher Attribute der nachfolgend behandelten Komponenten sowie der vorhandenen Methoden.
Schauen wir uns jetzt aber die Komponenten und deren Klassen in Java und JavaFX genauer an.
141 Das Kapitel wird dennoch sehr lang.
206
Swing-Applikationen mit JavaFX Script
> >
>
HINWEIS
Die Namen der Komponenten-Klassen in JavaFX entsprechen im Wesentlichen denen der AWTKlassen – nicht der Swing-Klassen, obgleich nicht alle Klassen des JavaFX Script APIs im AWT vorhanden sind. In Swing wird in der Regel eine Klasse mit einem J (für Java) beginnen. In JavaFX hat man darauf wieder verzichtet und die Namenslogik wie im AWT verwendet. Das darf aber nicht täuschen – im Hintergrund werden in der Regel die Swing- und nicht die AWT-Klassen verwendet.
5.4 Frames beziehungsweise Fenster, Container und Panels Um eine grafische Benutzeroberfläche aufbauen zu können, benötigen Sie in jedem Fall erst einmal eine Art Container. Solche Container sind Ordnungsstrukturen für Gruppen von Komponenten, die gemeinsam verwaltet werden. Das mag jetzt erst einmal sehr abstrakt klingen, ist aber eigentlich ganz logisch. Eine Schaltfläche ohne ein Fenster, in dem sie integriert ist, macht wenig Sinn. Genauso wenig hat die Komponente »Bildlaufleiste« ohne ein Fenster, das über sie gescrollt werden kann, eine nützliche Funktion. Die Komponenten müssen mittels der Container in verwaltbaren Gruppen organisiert werden. Container kann man im Wesentlichen in Fenster beziehungsweise Frames und so genannte Panels unterteilen.
5.4.1 Frames Frames sind voll funktionsfähige Fenstersegmente beziehungsweise Fenster mit eigenem Titel und Icon, wie man sie unter einem grafischen User-Interface erwartet. Allgemein gilt, dass es in Java verschiedene Klassen gibt um grafische Fenster zu erstellen. Beispielsweise die Window-Klasse im AWT. Diese enthält bereits grundlegende Eigenschaften für Fenster. In der Praxis wird jedoch unter Java selten Window direkt verwendet, sondern deren Subklassen java.awt.Frame oder javax.swing.JFrame. Diese verfügen über weiter gehende Fähigkeiten. In JavaFX kommt javafx.ui.Frame zum Einsatz, was wir schon mehrfach verwendet haben und eine Kapselung von JFrame darstellt.
5.4.2 Panels Bei einem Panel handelt es sich um einen reinen Container, der keine sichtbaren Bestandteile besitzt. Es handelt sich insbesondere um kein eigenes Fenster. Einziger Zweck eines Panels ist es, Komponenten aufzunehmen und anzuordnen, die dann über das Panel einem Fenster hinzugefügt werden und nicht mehr direkt. Im AWT verwendet man für Panels die Klasse java.awt.Panel und in Swing javax.swing.JPanel.
207
Kapitel 5
In JavaFX kapselt die Klasse javafx.ui.Panel ein JPanel.
> >
>
HINWEIS
Panels können auch verschachtelt werden.
5.5 Rahmen und Layoutmanager Wie schon erwähnt verfolgte Sun bei Java von Anfang an das Konzept, die Gestaltung einer grafischen Oberfläche bei einem Anwender automatisiert an die dort vorhandenen Gegebenheiten anzupassen. Bei einer typischen Java-Applikationen werden Sie sich (scheinbar) überhaupt nicht um die genauen Positionen der Komponenten innerhalb eines Fensters beziehungsweise Containers kümmern. Sie werden einfach »irgendwo« auf der Oberfläche platziert und in der Größe angepasst. Bei einer typischen Java-Applikation mit einem sehr flexiblen Layoutmanager kann es passieren, dass sich die Größe des Applikationsfensters verändert und Komponenten an ganz anderen Stellen auftauchen als bei der Originalgröße. Oder deren Größe ist verändert. Diese Anpassungen sind jedoch wie gesagt nicht zufällig. Das Verhalten wird automatisch im Hintergrund durch Layoutmanager verwaltet. Das AWT beinhaltete ursprünglich fünf verschiedene Typen von Layoutmanagern, um über diese die Oberfläche einer grafischen Applikation unterschiedlich anzuordnen: Ein FlowLayout sorgt dafür, dass Komponenten in der Reihenfolge, in der sie in den Container eingefügt werden, spaltenweise einfach von links nach rechts angeordnet werden, bis keine weiteren Komponenten mehr in eine Zeile passen. Dann geht es zur nächsten Zeile und analog weiter. Die Breite jeder Komponente ergibt sich aus dem Platz, den sie benötigt, um ihren Inhalt darzustellen. So wird eine Schaltfläche mit der Beschriftung OK weniger Platz bekommen als eine Schaltfläche mit der Beschriftung ABBRUCH. Die Höhe der Zeilen wird von der Höhe der Elemente, die in der Reihe platziert sind, bestimmt. Besonders interessant ist, dass die Veränderung der Größe eines Fensters dazu führen kann, dass Komponenten in die nächste Zeile verlagert oder nach oben geholt werden. Beim GridLayout wird ein Rasterlayout mit Zeilen und Spalten verwendet (eine Art virtuelle Tabellenstruktur). Ein Container wird wie ein Gitter mit gleich großen Teilen behandelt. Jede eingefügte Komponente wird in einer Zelle des Gitters platziert. Dabei ist wieder die Reihenfolge relevant, in der eine Komponente hinzugefügt wurde. Die Anordnung beginnt immer oben links und geht dann wie bei FlowLayout von links nach rechts weiter. Ein wesentlicher Unterschied zwischen dem GridLayout und dem FlowLayout ist, dass ein Objekt vom Typ GridLayout jeder Komponente den gleichen Raum zur Verfügung stellt.
208
Swing-Applikationen mit JavaFX Script
Beim BorderLayout handelt es sich um ein Rahmenlayout. Komponenten werden dem Container nach geografischen Aspekten zugeordnet (wie bei einem Kompass). Es gibt fünf Gebiete, in denen eine Komponente platziert werden kann. Dies sind das Zentrum (Center), Nord (North), Süd (South), Ost (East) und West (West). Ein CardLayout bedeutet, dass von den enthaltenen Komponenten immer nur eine Komponente sichtbar ist. Der CardLayout-Layoutmanager behandelt die dem Container hinzugefügten Komponenten wie einen Stapel von Karten, von denen nur die oberste sichtbar ist. Der GridBagLayout-Layoutmanager unterteilt einen Container in ein Gitter mit gleich großen Zellen. Dabei legt der Layoutmanager die Anzahl der Zeilen und Spalten fest, was diesen Layoutmanager von dem GridBag unterscheidet. Der andere wichtige Unterschied ist der, dass eine Komponente mehr als eine Zelle belegen kann. Unter Swing kamen nun noch ein paar weitere Layoutmanager hinzu. Unter anderem diese zwei: Das BoxLayout enthält entweder vertikal oder horizontal mehrere Komponenten, die auch bei Größenveränderungen des umgebenden Containers statisch angeordnet bleiben. In ganz neuen Versionen des JDK gibt es ein StackLayout als Erweiterung des CardLayout.
> >
>
HINWEIS
Beachten Sie, dass die Layoutmanager des AWT unter Swing weiterverwendet werden und damit auch unter JavaFX unmittelbar zum Einsatz kommen.
Swing stellt nun zur Gestaltung von Oberflächen auch so genannte Rahmen zu Verfügung, die auch unter JavaFX verwendet werden. Das sind rechteckige Ordnungscontainer, die verschiedene Arten an Rahmenlinien um ihren Inhalt anzeigen können.
5.5.1 Die deklarative Verwendung von Rahmen und Layoutmanagern in JavaFX In JavaFX kann nun auch die Verwendung von Rahmen als auch Layoutmanager deklarativ erfolgen. Jeder Swing/AWT-Layoutmanager ist in einer JavaFX-Klasse eingeschlossen, die ein JPanel mit dem angegebenen Layoutmanager instanziert. Komponenten werden dem zu Grunde liegenden JPanel auf deklarative Weise hinzugefügt, indem die Attribute verwendet werden, die die jeweilige JavaFX-Klasse bereitstellt.
209
Kapitel 5
Die nachfolgende Tabelle zeigt das Zusammenspiel zwischen Layoutmanagern in Java und den ummantelnden JavaFX-Klassen (Widgets), die allesamt im Paket javafx.ui zu finden sind: JavaFX Widget
Layoutmanager in Java
GridPanel
GridLayout
GridBagPanel
GridBagLayout
FlowPanel
FlowLayout
BorderPanel
BorderLayout
Box
BoxLayout
StackPanel
StackLayout (eine spezielle Variante von einem Programmierer mit
Namen Romain Guy) CardPanel
CardLayout
GroupPanel
org.jdesktop.layout.GroupLayout
Tabelle 5.1: Gegenüberstellung von JavaFX-Widgets und korrespondierenden Layoutmanagern
!
!
!
ACHTUNG
Beachten Sie, dass es in JavaFX verschiedene Klassen gibt, die in der Bedeutung nicht den gleichnamigen Java-Klassen entsprechen. So gibt es in JavaFX eine Klasse GridPanel im Paket javafx.ui.canvas, die nicht das Äquivalent zum Layoutmanager GridPanel ist.
Ebenso wie jeder Layoutmanager wird jeder Rahmentyp aus Swing in eine JavaFXKlasse eingeschlossen, deren Attribute mit dem Konfigurationsoptionen des jeweiligen Rahmens korrespondieren. Sämtliche Klassen zum Erzeugen eines Rahmens sind im Paket javafx.ui zu finden. Nachfolgend finden Sie eine Zusammenfassung der Klassen in JavaFX zum Erzeugen eines Rahmens und wie sie mit den Swing-Klassen für Rahmen im Paket javax.swing. border korrespondieren: JavaFX
Swing
EmptyBorder
EmptyBorder
LineBorder
LineBorder
BevelBorder
BevelBorder
SoftBevelBorder
SoftBevelBorder
MatteBorder
MatteBorder
TitledBorder
TitledBorder
Tabelle 5.2: Die Namen der JavaFX-Klassen entsprechen den Swing-Klassen
210
Swing-Applikationen mit JavaFX Script
5.5.2 Ein Beispiel mit Rahmen und Layoutmanager Das nachfolgende einfache Beispiel verwendet den Rahmen EmptyBorder und den Layoutmanager GridPanel (layoutmanagerrahmen1): 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
import javafx.ui.*; class ButtonClickModel { attribute anzahlKlicks: Number; } var model = new ButtonClickModel(); Frame { width: 300 height: 200 content: GridPanel { border: EmptyBorder { top: 30 left: 30 bottom: 30 right: 30 } rows: 2 columns: 1 vgap: 10 cells: [Button { text: "Fang mich, ich bin der Fruehling" mnemonic: I action: operation() { model.anzahlKlicks++; } }, Label { text: bind "Anzahl der Klicks auf den Button: {model.anzahlKlicks}" }] } visible: true };
Listing 5.5: Ein Programm mit einem Layoutmanager und einer Rahmenklasse
Wenn Sie das Programm ausführen, erhalten Sie ein kleines Fenster mit einer Schaltfläche und einem Label, das einen gewissen Text anzeigt. Der Textinhalt des Labels wird in Zeile 31 an das Attribut model.anzahlKlicks über den Operator bind gebunden und baut damit eine Beziehung zu der Änderung von dessen Wert auf. Über das Attribut model.anzahlKlicks wird ein Counter verwaltet, der die Anzahl der Klicks auf die
211
Kapitel 5
Schaltfläche mitzählt. Das bedeutet, der Text in dem Label ändert sich mit jedem Klick auf die Schaltfläche. Ebenso können Sie die Aktion der Schaltfläche mit der Tastenkombination ALT + I auslösen.
Abbildung 5.4: Ein Fenster mit einer Schaltfläche und einem Label
> >
>
HINWEIS
In dem Beispiel werden einige Techniken wie das Attribut mnemonic von einer Schaltfläche eingesetzt, die wir in Kürze genauer besprechen werden.
In unserem Beispiel wird der Layoutmanager GridPanel durch Zuweisung von Werten zu den entsprechenden Attributen so konfiguriert, dass er eine Spalte (Zeile 20 – columns: 1) und zwei Reihen (Zeile 19 – rows: 2) besitzt sowie einen vertikalen Abstand von 10 Pixel zwischen den Reihen (Zeile 21 – vgap: 10). TIPP
Der Layoutmanager GridPanel besitzt ebenso natürlich ein Attribut hgap zum Festlegen eines Abstands zwischen den Spalten.
Die Zeilen 13 bis 18 legen über das Attribut border und die deklarative Wertzuweisung der Klasse EmptyBorder fest, dass ein unsichtbarer Rahmen auf allen vier Seiten um den Inhalt gelegt wird: 13 border: EmptyBorder { 14 top: 30 15 left: 30 16 bottom: 30 17 right: 30 18 } Listing 5.6: Festlegen eines unsichtbaren Rahmens
212
Swing-Applikationen mit JavaFX Script
Die Schaltfläche und das Label werden über die Eigenschaft cells in den Zeilen 22 bis 32 sequenziell Zellen des Layoutmanagers hinzugefügt: 22 23 24 25 26 27 28 29 30 31 32
cells: [Button { text: "Fang mich, ich bin der Fruehling" mnemonic: I action: operation() { model.anzahlKlicks++; } }, Label { text: bind "Anzahl der Klicks auf den Button: {model.anzahlKlicks}" }]
Listing 5.7: Die Schaltfläche und das Label werden zwei Zellen hinzugefügt
> >
>
HINWEIS
Die Implementierung von GridPanel reagiert auf das Einfügen und Löschen in Zellen über das Attribut cells mit dem Hinzufügen oder Entfernen von Komponenten von dem implizit zu Grunde liegenden javax.swing.JPanel.
5.6 Schaltflächen Schaltflächen müssen sicher in der Funktionalität nicht erklärt werden. Sie werden in Java ganz einfach als Instanz der Klasse java.awt.Button (AWT) beziehungsweise javax.swing.JButton erzeugt. In JavaFX verwenden Sie die Klasse javafx.ui.Button. Die Klasse Button kapselt in JavaFX die Swing-Komponente JButton. Wir wollen uns am Beispiel von Schaltflächen ein paar wichtige (nicht alle) Attribute dieser Klasse genauer ansehen, die allesamt öffentlich (public) deklariert sind und sich für verschiedene andere Komponenten wiederholen: Attribut
Beschreibung
borderPainted: Boolean
Die Festlegung, ob ein Rahmen gezeichnet wird, wenn eine Schaltfläche einen solchen hat. Der Vorgabewert ist true.
contentAreaFilled: Boolean
Die Festlegung, ob diese Schaltfläche den gesamten Anzeigebereich deckend ausfüllt. Wenn man diese Eigenschaft auf false setzt, kann man eine transparente Schaltfläche erzeugen. Der Vorgabewert ist true.
defaultButton: Boolean
Dieses Attribut bestimmt, ob eine Schaltfläche der Defaultbutton in dem aktuellen Dialog ist.
Tabelle 5.3: Wichtige Attribute der Klasse Button
213
Kapitel 5
Attribut
Beschreibung
defaultCancelButton: Boolean
Dieses Attribut bestimmt, ob eine Schaltfläche der Defaultbutton für die Abbruchaktion in dem aktuellen Dialog ist.
horizontalAlignment: HorizontalAlignment
Die Festlegung der horizontalen Ausrichtung von dem Inhalt der Schaltfläche (Icon und Text). Das Attribut kann einen der folgenden Werte annehmen: CENTER (zentriert) LEADING (führend) TRAILING (folgend – der Vorgabewert)
horizontalTextPosition: HorizontalAlignment
Die Festlegung der horizontalen Position des Textes relativ zu einem Icon. Das Attribut kann einen der folgenden Werte annehmen: CENTER (zentriert) LEADING (führend) TRAILING (folgend – der Vorgabewert)
icon: Icon
Die Festlegung des Default-Icons der Schaltfläche
mnemonic: KeyStroke
Die Festlegung des Zeichens, das als Shortcut für die Schaltfläche fungieren soll. Wenn Sie die Taste ALT zusammen mit diesem Zeichen drücken, wird die Aktion ausgelöst, die mit dieser Schaltfläche verbunden ist.
text: String
Dies dürfte sicher eines der wichtigsten Attribute einer Schaltfläche sein. Es ist die Festlegung der Textbeschriftung von der Schaltfläche.
verticalAlignment: VerticalAlignment
Die Festlegung der vertikalen Ausrichtung von dem Inhalt der Schaltfläche (Icon und Text). Das Attribut kann einen der folgenden Werte annehmen: CENTER (zentriert – der Vorgabewert) TOP (oben) BOTTOM (unten)
verticalTextPosition: VerticalAlignment
Die Festlegung der vertikalen Position des Textes relativ zu einem Icon. Das Attribut kann einen der folgenden Werte annehmen: CENTER (zentriert – der Vorgabewert) TOP (oben) BOTTOM (unten)
Tabelle 5.3: Wichtige Attribute der Klasse Button (Fortsetzung)
214
Swing-Applikationen mit JavaFX Script
5.6.1 Ein Beispiel mit Schaltflächen Schauen wir uns zur Demonstration der Attribute einer Schaltfläche ein vollständiges Beispiel an (schaltflaeche): 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
import javafx.ui.*; // Eine Klasse zum Aktivieren und Deaktivieren einer Schaltfläche class ButtonDemoModel { attribute buttonAktiviert: Boolean; } // Ein Model-Objekt aus der Klasse wird erzeugt var model = ButtonDemoModel { buttonAktiviert: true };
// Das deklarative Erzeugen eines View-Objektes aus der Klasse // javafx.ui.Frame. Dieses Objekt repräsentiert sowohl die vollständige // Benutzerschnittstelle des Programms als auch das gesamte Programm // selbst Frame { // Titelzeile des Fensters title: "ButtonDemo" // Der Inhalt des Frames – ein FlowPanel content: FlowPanel { // Der Inhalt des FlowPanels – 3 Button content: // Button 1 – im FlowPanel zuerst eingefügt und damit links // angeordnet [Button { // Beschriftung text: "Deaktiviere Button in der Mitte" // vertikale Ausrichtung des Textes verticalTextPosition: CENTER // horizontale Ausrichtung des Textes horizontalTextPosition: LEADING // Icon auf dem Button icon: Image { url: "http://www.javafx-buch.de/demobilder/b_rechts.gif" } // Shortcut mnemonic: D // Text des Tooltipps – vererbt von javafx.ui.Widget toolTipText: "Klicken Sie auf diesen Button, um den Button in der Mitte zu deaktivieren" 41 // Zustand der Aktivierung – bidirektional an die 42 // Eigenschaft model.buttonAktiviert gebunden 43 enabled: bind model.buttonAktiviert
// Die ausgelöste Aktion action: operation() { // Button in der Mitte wird deaktiviert model.buttonAktiviert = false; } }, // Button 2 – im FlowPanel als Zweites eingefügt und damit // in der Mitte angeordnet Button { text: "Ich stehe in der Mitte" icon: Image { url: "http://www.javafx-buch.de/demobilder/b_mitte.gif" } verticalTextPosition: BOTTOM horizontalTextPosition: CENTER mnemonic: M toolTipText: "Bei dem Button ist keine Aktivitaet hinterlegt" enabled: bind model.buttonAktiviert }, // Button 3 – im FlowPanel als Letztes eingefügt und damit // rechts angeordnet Button { text: "Aktiviere Button in der Mitte" icon: Image { url: "http://www.javafx-buch.de/demobilder/b_links.gif" } mnemonic: A toolTipText: "Klicken Sie auf diesen Button, um den Button in der Mitte zu aktivieren" action: operation() { model.buttonAktiviert = true; } enabled: bind not model.buttonAktiviert }]
74 75 76 77 78 79 } 80 visible: true 81 }
Listing 5.8: Ein Beispiel mit drei Schaltflächen
In den Zeilen 4 bis 6 finden Sie die Deklaration einer Klasse zum Aktivieren und Deaktivieren einer Schaltfläche. Diese stellt das Boolesche Attribut buttonAktiviert zur Verfügung. Je nach Zustand dieses Attributs soll eine Schaltfläche aktiviert beziehungsweise deaktiviert werden.
216
Swing-Applikationen mit JavaFX Script
Abbildung 5.5: Das Beispiel nach dem Laden – der linke und der mittlere Button sind aktiviert
> >
>
HINWEIS
Wohlbemerkt – es handelt sich hier nur um eine gewöhnliche Klasse mit einem Booleschen Attribut, die in der Folge nur auf diese spezielle Weise verwendet wird. Man könnte die Klasse auch für eine beliebige andere Aktion verwenden, bei der ein Objekt mit einem Booleschen Attribut benötigt wird.
In den Zeilen 9 bis 11 wird ein Model-Objekt aus der Klasse erzeugt und das Attribut buttonAktiviert mit dem Wert true initialisiert. In den Zeilen 17 bis 81 sehen Sie das deklarative Erzeugen eines View-Objektes aus der Klasse javafx.ui.Frame. Dieses Objekt repräsentiert sowohl die vollständige grafische Benutzerschnittstelle des Programms als auch das gesamte Programm selbst.
Das FlowPanel für die gesamte GUI Nach der Zeile 19 mit der Titelzeile des Fensters ist die Zeile 21 wieder von Interesse. Der gesamte Inhalt des Frames besteht aus einem FlowPanel. Dieses wird dem Attribut content zugewiesen. Die Implementierung des damit erzeugten Objektes erstreckt sich bis Zeile 79.
Drei Schaltflächen als Inhalt Innerhalb des FlowPanel-Objekts werden drei Schaltflächen als Inhalt platziert. Wie üblich wird wieder die Eigenschaft content (dieses Mal aber von dem FlowPanelObjekt) verwendet – ab Zeile 23. Konkret beginnt die Festlegung des Inhalts ab Zeile 26 mit der öffnenden eckigen Klammer und erstreckt sich bis zu Zeile 78. Die deklarative Erzeugung der ersten Schaltfläche erstreckt sich von Zeile 26 bis Zeile 49. Da diese Schaltfläche im FlowPanel zuerst eingefügt wird, wird sie in dem Panel damit links angeordnet. Für die Schaltfläche wird eine Beschriftung (Zeile28 – text: "Deaktiviere Button in der Mitte"), eine zentrierte vertikale Ausrichtung des Textes (Zeile 30 – verticalTextPosition: CENTER) und die führende horizontale Ausrichtung des Textes (Zeile 32 – horizontalTextPosition: LEADING) festgelegt.
217
Kapitel 5
Die Klasse javafx.ui.Image Diverse Möglichkeiten einer Schaltfläche zeigen sich erst dann, wenn neben Text auch eine Grafik (ein Icon) angezeigt wird. Über die Eigenschaft icon in Zeile 34 wird so eine Grafik zugeordnet. Dabei wird wieder deklarativ aus der Klasse javafx.ui.Image ein Objekt erzeugt. Die Klasse stellt ein Attribut url zu Verfügung, über das Sie in Zeile 35 eine Grafik aus dem Internet nachladen können: url: http://www.javafx-buch.de/demobilder/b_rechts.gif TIPP
Das url-Attribut von Objekten vom Typ javafx.ui.Image ist recht flexibel. Es kann einfach eine Adresse als String zugewiesen bekommen, der einen URL auf die gewünschte Bildressource beschreibt. JavaFX verfügt über einen internen Cache für Bilder, der sogar das Laden von Bildern aus JAR-Dateien unterstützt. Dabei wird der Java Class Loader verwendet. Damit können auch Bilder in JAR-Dateien auf einfache Weise verwendet werden.
Shortcut und Tooltip In der Zeile 38 wird ein Shortcut für die Schaltfläche festgelegt (mnemonic: D). Diese wird ausgelöst, wenn der Anwender die Tastenkombination ALT + D drückt. In der Zeile 40 sehen Sie die Festlegung eines Textes für den Tooltipp, der angezeigt wird, wenn der Mauszeiger über die Schaltfläche geführt wird.
Aktivieren und Deaktivieren In Zeile 43 wird das Attribut enabled, das den Zustand der Aktivierung steuert, an die Eigenschaft model.buttonAktiviert gebunden: enabled: bind model.buttonAktiviert
Die konkrete Aktion Von Zeile 45 bis 48 wird die ausgelöste Aktion beim Klick auf die Schaltfläche über das Attribut action beschrieben. Sie sehen in Zeile 47, dass das Attribut model.buttonAktiviert den Wert false zugewiesen bekommt. Das ist gleichbedeutend damit, dass die Schaltfläche in der Mitte deaktiviert wird. Die beiden weiteren Schaltflächen in dem Beispiel werden vollkommen analog aufgebaut, wobei mit der rechten Schaltfläche die mittlere Schaltfläche wieder aktiviert werden kann. Beachten Sie ebenso, dass der Klick auf die linke Schaltfläche diese deaktiviert und der Klick auf die rechte Schaltfläche die direkte Schaltfläche deaktiviert. Für die mittlere Schaltfläche ist keine Reaktion implementiert.
218
Swing-Applikationen mit JavaFX Script
Abbildung 5.6: Das Beispiel nach dem Klick auf den linken Button – der mittlere und der linke Button sind deaktiviert, der rechte ist aktiviert und zeigt den Tooltipp an
5.7 Menüs Jedes Fenster/Frame einer grafischen Applikation kann eine eigene Menüleiste besitzen. Jede Menüleiste kann mehrere Menüs enthalten und dort jedes Menü wieder beliebige Einträge142. Das AWT enthält zum Erzeugen von Menüs die Klassen javafx.ui.MenuBar, javafx.ui.Menu und javafx.ui.MenuItem. Das Erzeugen einer Menüleiste erfolgt so: 1. Zuerst erstellen Sie eine Instanz der Klasse MenuBar. Das steht für die »Titelzeile« des Menüs. 2. Dann werden über Instanzen von Menu Menüs erzeugt und in der Menüzeile verankert. 3. Und diese einzelnen Menüs müssen über Objekte vom Typ MenuItem mit konkreten Einträgen gefüllt werden. 4. Und dann muss noch ein Reaktionsmechanismus aufgebaut werden. Offensichtlich ist dieser Aufbau ziemlich mühsam. Aber auch unter Swing sind das Erzeugen von Menüs und vor allem die Implementierung von Reaktionen nicht trivial. Und obwohl auch in JavaFX die Klassen MenuBar, Menu und MenuItem143 zum Kapseln der entsprechenden Swing-Klassen verwendet werden, hat die deklarative Erzeugung gerade bei Menüs eine sehr starke Vereinfachung und vor allem eine stringentere Logik gebracht. Greifen wir zum Aufbau eines Menüs auf den Beispielcode von der dynamischen Model/View-Version des Hallo-Welt-Programms von oben zurück und fügen ein einfaches Menü hinzu (menue1): 01 import javafx.ui.*; 02 import java.lang.System; 03 142 Halt so, wie man Menüs kennt. 143 Nur halt wie üblich aus dem Paket javafx.ui.
219
Kapitel 5 04 class ButtonClickModel { 05 attribute anzahlKlicks: Number; 06 } 07 08 var model = new ButtonClickModel(); 09 10 Frame { 11 width: 300 12 height: 200 13 menubar: MenuBar { 14 menus: Menu { 15 text: "Datei" 16 mnemonic: D 17 items: MenuItem { 18 text: "Exit" 19 mnemonic: X 20 accelerator: { 21 modifier: ALT 22 keyStroke: F4 23 } 24 action: operation() { 25 System.exit(0); 26 } 27 } 28 } 29 } 30 content: GridPanel { ... Listing 5.9: Das erweiterte Beispiel mit einem Menü
Das Beispiel verfügt nun über ein Menü, über das das Programm beendet werden kann.
Abbildung 5.7: Ein Menü
220
Swing-Applikationen mit JavaFX Script
Zuerst einmal ist von Bedeutung, dass jeder Frame in JavaFX über das Attribut menubar verfügt. In Zeile 13 wird dem Frame in dem Beispiel ein Objekt vom Typ MenuBar zugeordnet. Die deklarative Erzeugung erstreckt sich bis Zeile 29. Als Erstes wird in Zeile 14 das Attribut menus mit einem Wert versehen. Konkret wird ein deklarativ erzeugtes Objekt vom Typ Menu zugewiesen. In Zeile 15 wird die Beschriftung des Menüeintrags festgelegt: text: "Datei"
In Zeile 16 sehen Sie, dass ein Shortcut für den Buchstaben D angelegt wird: mnemonic: D
Ab Zeile 17 bis 27 finden Sie die Menüeinträge. Genau genommen ist es in diesem Fall nur ein Eintrag, der dem Attribut items zugeordnet wird. Die deklarative Erzeugung eines Objekts vom Typ MenuItem ist nach den bisherigen Ausführungen natürlich auch nicht mehr schwer zu verstehen. In Zeile 18 sehen Sie die Beschriftung und in Zeile 19 den Shortcut. In den Zeilen 20 des 23 wird über das Attribut accelerator eine Tastenkombination festgelegt, über die alternativ der zugeordnete Menübefehl ebenso direkt aufgerufen werden kann. Für das Beispiel setzen wir das Beenden des Programms um und dafür benutzt man allgemein die Tastenkombination ALT + F4. Die beiden Attribute modifier und keyStroke gestatten die Festlegung. In den Zeilen 24 bis 26 wird über das Attribut action eine Operation zugeordnet, die das Programm mit System.exit(0); beendet.
5.8 Labels – eine ultimative Möglichkeit zur dynamischen Oberflächengestaltung Ein Label ist eine Komponente zur Beschriftung einer anderen Komponente oder zum Anzeigen eines Textes. Sie ist im allgemeinen Fall die wohl einfachste Form einer Komponente in einer Benutzeroberfläche ohne große Möglichkeiten und mit nur wenigen interessanten aktiven Ereignissen. Das gilt so nun aber nicht in JavaFX! Sie dürfen JavaFX bei Labels nicht unterschätzen. Oder formulieren wir es präziser – Labels sind in JavaFX fast eine ultimative Möglichkeit zur dynamischen Oberflächengestaltung! Label basieren in Java auf der Klasse java.awt.Label beziehungsweise javax.swing.JLabel. In JavaFX kommt die Klasse javafx.ui.Label zum Einsatz, die nicht nur ein JLabel kapselt, sondern erheblich erweiterte Fähigkeiten bereitstellt.
221
Kapitel 5
5.8.1 Labels mit HTML und CSS Labels in JavaFX können mit den entsprechenden Attributen auf alle Arten formatiert werden, die für Texte sinnvoll sind144. Das wollen wir hier gar nicht weiter ausführen, da es sowohl recht primitiv ist als auch sich in vielen anderen Komponenten zur Darstellung von Text wiederholt. Aber die Besonderheit in JavaFX ist, dass die Klasse Label direkt die Anzeige von HTML-Inhalt samt der Gestaltung mit CSS unterstützt! Und das bedeutet, Sie können unter der Verwendung eines primitiven Labels formatierten Text oder Bilder mit HTML und CSS zur Gestaltung einer JavaFX-Oberfläche145 verwenden. Ganz so wie Sie eine typische Webapplikation erstellen würden. Zusätzlich können Sie alle in JavaFX verfügbare Ausdrücke verwenden, um dynamischen HTML-Inhalt in einer Swing-Applikation genauso leicht anzuzeigen, wie das mit diversen Tools zur Erstellung von Webseiten gemacht wird.146
> >
>
HINWEIS
Ist Ihnen die Bedeutung dieser Möglichkeiten eines JavaFX-Labels klar? Ein Programmierer braucht weder Java zu kennen noch besonders weit gehende Kenntnisse in JavaFX, um eine dynamische GUI zu erzeugen. Zum Erzeugen einer dynamischen Oberfläche genügen HTML-Grundlagen (und gegebenenfalls einige Kenntnisse in Style Sheets, was aber nicht mal unbedingt notwendig ist). Dies erweitert die Zielgruppe für die Anwendung von JavaFX erheblich. Im Extremfall erzeugt man für die Oberfläche einer JavaFX-Applikation nur einen primitiven Frame, der außer dem Attribut text fast nur reines HTML sowie unter Umständen einige Style Sheets enthält. Und dennoch erhält man im Endeffekt eine Java-Oberfläche. Wer Erfahrungen mit der händischen Programmierung von dynamischen Oberflächen unter Swing hat, wird einschätzen können, was dieses bedeutet146. JavaFX geht damit sozusagen den umgekehrten Weg wie Java-Toolkits, wie beispielsweise das GWT (Google Web Toolkit), welches die Gestaltung von Weboberflächen mit reinem Java (also ohne direkten Kontakt zu HTML, Javascript und CSS) gestattet, die vor der tatsächlichen Ausführung in ein solches Gemisch aus HTML, Javascript und Style Sheets übersetzt werden.
Betrachten wir ein praktisches Beispiel (label1): 01 import javafx.ui.*; 02 03 class Seiten { 04 attribute id: String; 05 attribute name: String; 06 attribute beschreibung: String; 07 attribute aktiv: Boolean; 08 attribute url: String;
144 Ausrichtung, Textart, Textgröße, Textstil,... 145 Und damit letztendlich einer Java-Oberfläche. 146 Natürlich darf man dabei nicht übersehen, dass mit einem Label noch lange nicht alle Widgets einer Oberfläche erzeugt werden können.
96 " 97 } 98 visible: true 99 } Listing 5.10: Eine JavaFX-Applikation mit einem Label, das HTML interpretiert
Das Beispiel zeigt ein Frame mit einem Label, indem eine komplexe HTML-Struktur inklusive Style Sheets interpretiert und dargestellt wird.
224
Swing-Applikationen mit JavaFX Script
Abbildung 5.8: Ein Programm mit einem Label, das HTML und CSS aufbereitet
In den Zeile 3 bis 9 sehen Sie die Deklaration einer Klasse Seiten mit verschiedenen Attributen. Ebenso sehen Sie in den Zeilen 11 bis 14 eine weitere Klasse mit zwei Attributen. Die Operation anzahlWebseiten() von Zeile 16 bis 20 ist nicht dadurch komplex. Es wird einfach die Größe eines Arrays über eine Schleife bestimmt. In Zeile 24 sehen Sie ein Attribut Webseiten.subTotal, an das diese Operation anzahlWebseiten() mit dem Operator bind gebunden wird. Die deklarative Erzeugung eines Objekts webseiten vom Typ Webseiten erstreckt sich von Zeile 26 bis 57. Dort werden deklarativ vier Objekte vom Typ Seiten erzeugt und hinzugefügt. Das ab Zeile 59 erzeugte Frame bekommt nur für das Attribut content einen Wert zugewiesen – ein Label. Und für dieses Label wird ebenfalls nur ein Attribut text gebunden mit einem Wert versehen. Alles was Sie von Zeile 62 bis 96 sehen, ist ein einziger String. Beachten Sie, dass in JavaFX ein String über mehrere Zeilen verteilt werden kann. Im Inneren finden Sie HTML-Tags, Text und Stylesheet-Angaben. Aber es wird im Inneren des Strings auch programmiert147. Beispielsweise in den Zeilen 75 bis 88. In den geschweiften Klammern finden Sie eine if-Anweisung, den Operator sizeof sowie Zugriffe auf die Repräsentation des aktuellen Schleifendurchlaufs (item) samt den daran hängenden Attributen. In dem Beispiel werden also die eingebetteten JavaFX-Ausdrücke zum dynamischen Erstellen der Zeilen einer HTML-Tabelle sowie des Inhaltes der Tabellenzellen verwendet.
147 Oder genauer – es werden Ausdrücke ausgewertet.
225
Kapitel 5
Das bedeutet aber auch, wenn sich irgendwelche Änderungen in den Objekten ergeben, von denen die Ausdrücke abhängen, wird sich der Inhalt der HTML-Tabelle und der Zellen automatisch anpassen.
!
!
!
ACHTUNG
In der derzeitigen Version des JavaFX-APIs werden nicht alle Befehle aus HTML unterstützt. Sie werden zum Beispiel sehen, dass die Hyperlinks in dem letzten Beispiel nicht ausgelöst werden, wenn der Anwender darauf klickt. Auch CSS wird nur eingeschränkt funktionieren. Darauf gehen wir gleich noch ein.
5.8.2 Bilder in HTML Natürlich können Sie auch Bilder in dem Label über den üblichen HTML-Tag angeben. Beispiel (labelmitbild): 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20
Das Attribut text enthält einfach HTML-Bildreferenzen. Die Möglichkeiten der Klasse Label in JavaFX sind aber damit bei weitem noch nicht ausgeschöpft. Die Klasse kapselt ein spezialisiertes JEditorPane, worüber man einen geteilten Bildspeicher verwenden kann, der sogar das Laden von Bildern aus JARDateien unter Verwendung des Java Class Loader unterstützt. Daher können Sie den
226
Swing-Applikationen mit JavaFX Script
normalen HTML-Tag auch verwenden, um mit einem normalen URL auf eine Datei in gepackten Bildressourcen zuzugreifen.
Abbildung 5.9: Ein Frame mit Bildern in einem Label
5.8.3 Webformulare mit einem Label realisieren Sie können mit reinem HTML sogar diverse Elemente eines Webformulars über ein Label in einer JavaFX-Oberfläche erzeugen und damit als normale Formularkomponenten in einer Java-GUI verwenden. Das sind etwa einzeilige und mehrzeilige Texteingabefelder, Kontrollkästchen etc. Was explizit in der aktuellen Version des JavaFX APIs nicht geht, sind leider Schaltflächen. Schauen wir uns ein Beispiel an (labelmitformular): 01 import javafx.ui.*; 02 03 Frame { 04 width: 600 05 height: 300
// Schaltflaechen in einem Formular gehen derzeit nicht // Schaltflaechen mit dem Tag Button außerhalb von einem Formular // gehen derzeit auch nicht content: Label { text: bind " " } visible: true }
Listing 5.12: Ein Webformular im Rahmen eines Labels
Abbildung 5.10: Die Elemente der Oberfläche sind mit einem Webformular in einem Label erzeugt
228
Swing-Applikationen mit JavaFX Script
Wie Sie deutlich in dem Beispiel erkennen können, wird die Schaltfläche, welche in dem Formular definiert wird, vollständig ignoriert und die Schaltfläche, die der HTML-Tag