Wie kann man das Layout einer JavaFX-Anwendung mit Cascading Stylesheets formatieren?
Cascading Style Sheets (CSS) sind ein mächtiges Werkzeug, das im Wesenlichen aus der Gestaltung von HTML-Seiten bekannt ist. Sein Prinzip besteht darin, sog. Selektoren bestimmte Eigenschaften (z.B. Farben, Ränder, Abstände, etc.) zuzuweisen. Auf den generellen Aufbau und allgemeinen Gebrauch der CSS kann an dieser Stelle nicht eingegangen werden. Hierzu sei z.B. auf das CSS-Tutorial der W3 Schools verwiesen.
JavaFX übernimmt die CSS in angepasster Form, wobei
sich so weit wie möglich an die W3C-Standards
gehalten wird.
Einen vollständigen
Überblick über den Aufbau und die Anwendung
von CSS in JavaFX bietet der JavaFX CSS Reference Guide. Das
in JavaFX verwendete Default-Stylesheet befindet sich
unter dem Pfad jfxrt.jar/com/sun/javafx/scene/control/skin/caspian/caspian.css.
CSS-Syntax
CSS-Anweisungen setzen sich aus einer Eigenschaft, einem zugehörigen durch Doppelpunkt (':') getrennten Wert und einem abschließenden Semikolon (';') zusammen. Dabei können mehrere Anweisungen in einem durch geschweifte Klammern gebildeten Block zusammengefasst werden. Das jeweils letzte Semikolon innerhalb eines Blocks kann entfallen.
Selektor-1 [, Selektor-2 [, ...] ] { Eigenschaft-1: Wert-1; ... Eigenschaft-n: Wert-n[;] }
Die Bezeichner der Eigenschaften entsprechen oft, jedoch keinesfalls immer, denjenigen des Web-CSS. Meist wird jedoch ein '-fx-' vorangestellt (-fx-background-color, -fx-font-family, etc.). Zudem gibt es eine Reihe an Eigenschaften, die speziell für JavaFX geschaffen wurden. Welche Eigenschaften schließlich auf welche Selektoren angewendet werden können erläutert wiederum die JavaFX CSS Reference
Selektoren
Die durch CSS formatierbaren Knoten (Node) des
Szenegraphen (scene graph) sind alle von den
abstrakten Klassen Region
oder Control
abgeleitet. Ihre Selektoren können durch die
Methode getTypeSelektor()
ermittelt werden,
sind meist identisch mit den Klassenbezeichnern und
entsprechen in ihrer Funktion den Elementtypen im
Web-CSS (z.B. table, div, img, etc.).
Darüber hinaus besitzen viele Knoten einen
vorvergebenen CSS-Klassenbezeichner und eine
String-Instanzvariable zum Speichern einer ID. Die
CSS-Klassenbezeichner können in der JavaFX CSS Reference
nachgeschlagen werden und entsprechen meist ebenfalls
dem JavaFX-Klassennamen. Sie übernehmen jedoch
nicht die in Java übliche CamelCase-Schreibweise,
sondern verwenden stattdessen die Kleinschreibung mit
Bindestrich (RadioButton
→ radio-button,
ScrollBar
→ scroll-bar,
etc.). Es muss beachtet werden, dass ein Knoten auch
mehreren CSS-Klassen angehören kann. Die ID ist
nicht vorbelegt.
RadioButton rb = new RadioButton(); System.out.println(rb.getTypeSelector()); // RadioButton System.out.println(rb.getStyleClass()); // radio-button System.out.println(rb.getId()); // null
Zuweisung von Styles
In JavaFX können Styles inline oder als in einer
externen Datei deklarierte Stylesheets zugewiesen
werden. Ein Inline-Style formatiert nur den
angesprochenen Knoten und überschreibt ggf.
vorangegangene Styles.
Um einem Knoten einen
Inline-Style zuzuweisen, kann die Methode setStyle()
der Klasse Node
verwendet werden.
Label label = new Label("Text auf Label"); label.setStyle("-fx-background-color: darksalmon; -fx-font-size: 20px");
Zentrale Stylesheets werden in einer gesonderten Datei
deklariert. Hierzu wird zunächst eine ObservableList
aller registrierten Stylesheets der Scene
ermittelt. Ihr kann dann mittels der Methode add()
wiederum der URL-String der neuen Stylesheet-Datei
beigefügt werden.
Scene scene = new Scene(new Group()); scene.getStylesheets().add(getClass().getResource("/styles/cssTest.css").toExternalForm());
In der Stylesheet-Datei werden die Styles der obigen Syntax gemäß deklariert. Als Selektoren können dabei der Typ-Selektor, eine CSS-Klasse oder eine ID, bzw. Kombinationen aus diesen dienen.
Label { -fx-background-color: #f31100; } .grid-pane { -fx-alignment: center; -fx-grid-lines-visible: true; -fx-hgap: 15; -fx-vgap: 15; } #rechts-unten { -fx-font-family:'serif'; -fx-font-size:30; }
@-Regeln
Ab JavaFX 8 werden einige @-Regeln (At-rules) unterstützt. So können weitere Stylesheets und Schriftdateien in eine Stylesheetdatei eingebunden werden. Hierbei sollten die Vorgaben des W3C hinsichtlich der Reihenfolge eingehalten werden.
@import "cssTest.css"; @font-face { font-family: 'orbitron'; font-weight: bold; src: url('/frameworks/javafx/css/orbitron-black.otf'); }
Ein Fenster mit und ohne Formatierung
Das folgende Beipiel zeigt ein einfaches Fenster ohne CSS-Formatierung:
import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.control.RadioButton; import javafx.scene.layout.GridPane; import javafx.stage.Stage; public class CSSTest extends Application { public static void main(String[] args) { launch(CSSTest.class, args); } @Override public void start(Stage primaryStage) throws Exception { Label lo = new Label("links oben"); Label ro = new Label("rechts oben"); Button lu = new Button("links unten"); RadioButton ru = new RadioButton("rechts unten"); GridPane gp = new GridPane(); gp.add(lo, 0, 0); gp.add(ro, 1, 0); gp.add(lu, 0, 1); gp.add(ru, 1, 1); Scene scene = new Scene(gp, 400, 150); primaryStage.setScene(scene); primaryStage.setTitle("JavaFX CSS-Test"); primaryStage.show(); } }
Das gleiche Fenster mit CSS-Formatierung:
import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.control.RadioButton; import javafx.scene.layout.GridPane; import javafx.stage.Stage; public class CSSTest extends Application { public static void main(String[] args) { launch(CSSTest.class, args); } @Override public void start(Stage primaryStage) throws Exception { Label lo = new Label("links oben"); Label ro = new Label("rechts oben"); ro.setStyle("-fx-background-color: darksalmon; -fx-font-size: 20px;"); Button lu = new Button("links unten"); lu.setStyle("-fx-text-fill: lightseagreen;"); RadioButton ru = new RadioButton("rechts unten"); ru.setId("rechts-unten"); GridPane gp = new GridPane(); gp.getStyleClass().add("grid-pane"); // CSS-Klassenname: grid-pane gp.add(lo, 0, 0); gp.add(ro, 1, 0); gp.add(lu, 0, 1); gp.add(ru, 1, 1); Scene scene = new Scene(gp, 400, 150); scene.getStylesheets().add(getClass().getResource("/styles/cssTest.css").toExternalForm()); primaryStage.setScene(scene); primaryStage.setTitle("JavaFX CSS-Test"); primaryStage.show(); } }
/*************** cssTest.css *****************/ @import "HelloJavaFXWorld.css"; @font-face { font-family: 'orbitron'; font-weight: bold; src: url('/frameworks/javafx/css/orbitron-black.otf'); } .root { -hell-oliv: #bcbc8f; } GridPane { -fx-background-color: -hell-oliv; } Label { -fx-background-color: #f31100; } .grid-pane { -fx-alignment: center; -fx-grid-lines-visible: true; -fx-hgap: 15; -fx-vgap: 15; } .pane { -fx-background-color: #f0f088; } #rechts-unten { -fx-font-family:'orbitron'; -fx-font-size:30; } /**************** HelloJavaFXWorld.css ******************/ .button { -fx-background-color: #f00; } .label { -fx-background-color: #0f0; }
Quellen
Wenn Ihnen javabeginners.de gefällt, freue ich mich über eine Spende an diese gemeinnützigen Organisationen.