{"id":1096,"date":"2011-08-22T12:48:40","date_gmt":"2011-08-22T10:48:40","guid":{"rendered":"http:\/\/www.tutego.de\/blog\/javainsel\/2011\/08\/deklarative-javafx-oberflchen-mit-fxml\/"},"modified":"2011-08-22T12:48:40","modified_gmt":"2011-08-22T10:48:40","slug":"deklarative-javafx-oberflchen-mit-fxml","status":"publish","type":"post","link":"https:\/\/www.tutego.de\/blog\/javainsel\/2011\/08\/deklarative-javafx-oberflchen-mit-fxml\/","title":{"rendered":"Deklarative JavaFX-Oberfl&auml;chen mit FXML"},"content":{"rendered":"<p>Den Szene-Graph \u00fcber Java Programmcode aufzubauen ist eine M\u00f6glichkeit, doch JavaFX erlaubt es auch, die Objekte \u00fcber XML zu konfigurieren. Das erlaubt es viel einfacher, grafische Oberfl\u00e4chen \u00fcber Gui-Builder aufzubauen und sauber das Layout (was) vom Code (wie) zu trennen.<\/p>\n<p>Die hierarchische Struktur von XML passt nat\u00fcrlich prima zu der Hierarchie, die es bei grafischen Oberfl\u00e4chen gibt: Ein Fenster enth\u00e4lt Container, die wiederum Elemente enthalten, usw. F\u00fcr unser kleines Beispiel soll eine Oberfl\u00e4che drei Elemente bieten: Eine Beschriftung, ein Textfeld und eine Schaltfl\u00e4che. Dr\u00fcckt der Anwender die Schaltfl\u00e4che, soll der Text im Textfeld in Gro\u00dfbuchstaben konvertiert werden.<\/p>\n<p>Die XML-Datei covert2UpperCase.fxml sieht so aus:<\/p>\n<pre class=\"csharpcode\"><span class=\"kwrd\">&lt;?<\/span><span class=\"html\">xml<\/span> <span class=\"attr\">version<\/span><span class=\"kwrd\">=&quot;1.0&quot;<\/span> <span class=\"attr\">encoding<\/span><span class=\"kwrd\">=&quot;UTF-8&quot;<\/span>?<span class=\"kwrd\">&gt;<\/span>\n\n<span class=\"kwrd\">&lt;?<\/span><span class=\"html\">import<\/span> <span class=\"attr\">javafx<\/span>.<span class=\"attr\">scene<\/span>.<span class=\"attr\">layout<\/span>.*?<span class=\"kwrd\">&gt;<\/span>\n<span class=\"kwrd\">&lt;?<\/span><span class=\"html\">import<\/span> <span class=\"attr\">javafx<\/span>.<span class=\"attr\">scene<\/span>.<span class=\"attr\">control<\/span>.*?<span class=\"kwrd\">&gt;<\/span>\n\n<span class=\"kwrd\">&lt;<\/span><span class=\"html\">HBox<\/span> <span class=\"attr\">xmlns:fx<\/span><span class=\"kwrd\">=&quot;http:\/\/javafx.com\/fxml&quot;<\/span>\n      <span class=\"attr\">fx:controller<\/span><span class=\"kwrd\">=&quot;com.tutego.insel.javafx.ButtonController&quot;<\/span><span class=\"kwrd\">&gt;<\/span>\n  <span class=\"kwrd\">&lt;<\/span><span class=\"html\">children<\/span><span class=\"kwrd\">&gt;<\/span>\n    <span class=\"kwrd\">&lt;<\/span><span class=\"html\">Label<\/span> <span class=\"attr\">text<\/span><span class=\"kwrd\">=&quot;Eingabe: &quot;<\/span> <span class=\"kwrd\">\/&gt;<\/span>\n    <span class=\"kwrd\">&lt;<\/span><span class=\"html\">TextField<\/span> <span class=\"attr\">fx:id<\/span><span class=\"kwrd\">=&quot;input&quot;<\/span> <span class=\"kwrd\">\/&gt;<\/span>\n    <span class=\"kwrd\">&lt;<\/span><span class=\"html\">Button<\/span> <span class=\"attr\">text<\/span><span class=\"kwrd\">=&quot;Konvertiere&quot;<\/span> <span class=\"attr\">onAction<\/span><span class=\"kwrd\">=&quot;#convertAction&quot;<\/span> <span class=\"kwrd\">\/&gt;<\/span>\n  <span class=\"kwrd\">&lt;\/<\/span><span class=\"html\">children<\/span><span class=\"kwrd\">&gt;<\/span>\n<span class=\"kwrd\">&lt;\/<\/span><span class=\"html\">HBox<\/span><span class=\"kwrd\">&gt;<\/span><\/pre>\n<style type=\"text\/css\">\n.csharpcode, .csharpcode pre\n{\n\tfont-size: small;\n\tcolor: black;\n\tfont-family: consolas, \"Courier New\", courier, monospace;\n\tbackground-color: #ffffff;\n\t\/*white-space: pre;*\/\n}\n.csharpcode pre { margin: 0em; }\n.csharpcode .rem { color: #008000; }\n.csharpcode .kwrd { color: #0000ff; }\n.csharpcode .str { color: #006080; }\n.csharpcode .op { color: #0000c0; }\n.csharpcode .preproc { color: #cc6633; }\n.csharpcode .asp { background-color: #ffff00; }\n.csharpcode .html { color: #800000; }\n.csharpcode .attr { color: #ff0000; }\n.csharpcode .alt \n{\n\tbackground-color: #f4f4f4;\n\twidth: 100%;\n\tmargin: 0em;\n}\n.csharpcode .lnum { color: #606060; }<\/style>\n<p>Die Hierarchie ist gut zu erkennen. Die interessanten Dinge sind andere:<\/p>\n<ol>\n<li>Zu Beginn gibt es eine Art import-Anweisung um Typnamen nicht voll qualifizieren zu m\u00fcssen. F\u00fcr den R\u00fcckgriff auf Grafiken muss &lt;?import javafx.scene.image.*?&gt; eingebunden werden und &lt;?import javafx.scene.*?&gt; f\u00fcr Group, Node oder \u00e4hnliches, was wir im Programm aber alles nicht nutzen.<\/li>\n<li>HBox hat zwei Attribute: Ein Attribut deklariert den Namensraum fx, ein anderes eine Klasse, den sogenannten Controller, der sp\u00e4ter die Ereignisbehandlung f\u00fcr den Klick \u00fcbernimmt. Die Typen in FXML hei\u00dfen genauso wie die Klassennamen. Nat\u00fcrlich k\u00f6nne auch eigene Klassen eingebaut werden, sofern sie mit &lt;?import&gt; bekannt gemacht wurden.<\/li>\n<li>Das TextField bekommt mit dem Attribut fx:id eine ID zugewiesen, unter der das Textfeld sp\u00e4ter erfragt werden kann. JavaFX geht noch einen Schritt weiter, und bildet das Objekt mit der ID automatisch auf ein Attribut der Controller-Klasse ab. Label und Schaltfl\u00e4che brauchen keine IDs, da sie nicht erfragt werden m\u00fcssen.<\/li>\n<li>Das Attribut onAction der Schaltfl\u00e4che referenziert Programmcode, der immer aufgerufen wird, wenn die Schaltfl\u00e4che gedr\u00fcckt wird. Hier kann direkt Java-Quellcode stehen, oder, wie in unserem Fall, ein # und der Name einer Methode, die in einem Controller deklariert werden muss. Den Klassenamen vom Controller haben wir am Wurzelelement deklariert.<\/li>\n<\/ol>\n<p>Die Ereignisbehandlung ist komplett aus der FXML-Datei rausgezogen und wandert in Controller-Klassen. Die eigene Klasse ButtonController, die voll qualifiziert bei fx:controller genannt wurde,<b> <\/b>enth\u00e4lt:<\/p>\n<p>com\/tutego\/insel\/javafx\/ButtonController.java<\/p>\n<pre class=\"csharpcode\">package com.tutego.insel.javafx;\n\nimport javafx.<span class=\"kwrd\">event<\/span>.ActionEvent;\nimport javafx.fxml.FXML;\nimport javafx.scene.control.TextField;\n\n<span class=\"kwrd\">public<\/span> <span class=\"kwrd\">class<\/span> ButtonController\n{\n  @FXML\n  <span class=\"kwrd\">private<\/span> TextField input;\n\n  @FXML\n  <span class=\"kwrd\">protected<\/span> <span class=\"kwrd\">void<\/span> convertAction( ActionEvent <span class=\"kwrd\">event<\/span> )\n  {\n    input.setText( input.getText().trim().toUpperCase() );\n  }\n}<\/pre>\n<style type=\"text\/css\">\n.csharpcode, .csharpcode pre\n{\n\tfont-size: small;\n\tcolor: black;\n\tfont-family: consolas, \"Courier New\", courier, monospace;\n\tbackground-color: #ffffff;\n\t\/*white-space: pre;*\/\n}\n.csharpcode pre { margin: 0em; }\n.csharpcode .rem { color: #008000; }\n.csharpcode .kwrd { color: #0000ff; }\n.csharpcode .str { color: #006080; }\n.csharpcode .op { color: #0000c0; }\n.csharpcode .preproc { color: #cc6633; }\n.csharpcode .asp { background-color: #ffff00; }\n.csharpcode .html { color: #800000; }\n.csharpcode .attr { color: #ff0000; }\n.csharpcode .alt \n{\n\tbackground-color: #f4f4f4;\n\twidth: 100%;\n\tmargin: 0em;\n}\n.csharpcode .lnum { color: #606060; }<\/style>\n<p>Drei Dinge fallen ins Auge:<\/p>\n<ol>\n<li>Die Controller-Klasse erweitert keine Schnittstelle.<\/li>\n<li>Die Annotation @FXML sagt, dass der Verweis auf das TextField-Objekt aus dem Szene-Graphen in die Variable input injiziert werden soll.<\/li>\n<li>Da in der FXML-Datei an der Schaltfl\u00e4che ein onAction=&quot;#convertAction&quot; steht, muss das zu einer Methode zugeordnet werden. Die Annotation @FXML an der Methode unter dem Namen convertAction stellt diese Beziehung her.<\/li>\n<\/ol>\n<p>Das Hauptprogramm ist nun relativ einfach:<\/p>\n<p>com\/tutego\/insel\/javafx\/FXMLDemo.java, start()<\/p>\n<pre class=\"csharpcode\">@Override\n<span class=\"kwrd\">public<\/span> <span class=\"kwrd\">void<\/span> start( Stage stage ) throws Exception\n{\n  Parent p = FXMLLoader.load( getClass().getResource( <span class=\"str\">&quot;covert2UpperCase.fxml&quot;<\/span> ) );\n  stage.setScene( <span class=\"kwrd\">new<\/span> Scene( <span class=\"kwrd\">new<\/span> Group( p ), 500, 400 ) );\n  stage.setVisible( <span class=\"kwrd\">true<\/span> );\n}<\/pre>\n<style type=\"text\/css\">\n.csharpcode, .csharpcode pre\n{\n\tfont-size: small;\n\tcolor: black;\n\tfont-family: consolas, \"Courier New\", courier, monospace;\n\tbackground-color: #ffffff;\n\t\/*white-space: pre;*\/\n}\n.csharpcode pre { margin: 0em; }\n.csharpcode .rem { color: #008000; }\n.csharpcode .kwrd { color: #0000ff; }\n.csharpcode .str { color: #006080; }\n.csharpcode .op { color: #0000c0; }\n.csharpcode .preproc { color: #cc6633; }\n.csharpcode .asp { background-color: #ffff00; }\n.csharpcode .html { color: #800000; }\n.csharpcode .attr { color: #ff0000; }\n.csharpcode .alt \n{\n\tbackground-color: #f4f4f4;\n\twidth: 100%;\n\tmargin: 0em;\n}\n.csharpcode .lnum { color: #606060; }<\/style>\n<p>Was noch alles mit FXML m\u00f6glich ist, beschreibt ein Dokument von Oracle: <a href=\"http:\/\/fxexperience.com\/wp-content\/uploads\/2011\/08\/Introducing-FXML.pdf\">http:\/\/fxexperience.com\/wp-content\/uploads\/2011\/08\/Introducing-FXML.pdf<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Den Szene-Graph \u00fcber Java Programmcode aufzubauen ist eine M\u00f6glichkeit, doch JavaFX erlaubt es auch, die Objekte \u00fcber XML zu konfigurieren. Das erlaubt es viel einfacher, grafische Oberfl\u00e4chen \u00fcber Gui-Builder aufzubauen und sauber das Layout (was) vom Code (wie) zu trennen. Die hierarchische Struktur von XML passt nat\u00fcrlich prima zu der Hierarchie, die es bei grafischen [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":"","_links_to":"","_links_to_target":""},"categories":[11,62],"tags":[],"class_list":["post-1096","post","type-post","status-publish","format-standard","hentry","category-insel","category-javafx"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/1096","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/comments?post=1096"}],"version-history":[{"count":0,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/1096\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/media?parent=1096"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/categories?post=1096"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/tags?post=1096"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}