Stufe 6Werkzeuge und Oberflächen · Lektion 34 von 34
ScalaFX: Oberflächen mit JavaFX
ScalaFX ist eine Scala-Schicht über JavaFX, dem modernen Oberflächen-Toolkit der Java-Welt. Es beschreibt Fenster und Bedienelemente als verschachtelte Objekte und verbindet Werte über Bindings – Oberflächen aktualisieren sich damit von selbst.
JavaFX und ScalaFX
JavaFX ist der Nachfolger von Swing: Es bringt hardwarebeschleunigte Grafik, Animationen, Styling mit CSS und ein Konzept für beobachtbare Werte (Properties) mit. Seit Java 11 gehört JavaFX nicht mehr zum JDK, sondern wird als eigenständiges Projekt (OpenJFX) entwickelt und wie eine gewöhnliche Bibliothek eingebunden. ScalaFX übernimmt diese Abhängigkeiten in der Regel gleich mit.
Die Stärke von ScalaFX ist eine deklarative Schreibweise: Statt Objekte zu erzeugen und Eigenschaften nacheinander zu setzen, beschreiben Sie die Oberfläche als Baum.
Einrichten
libraryDependencies += "org.scalafx" %% "scalafx" % scalafxVersion
fork := trueFür scalafxVersion tragen Sie die aktuelle Version von der Projektseite ein; sie orientiert sich an der JavaFX-Version (zum Beispiel beginnt eine Version für JavaFX 21 mit „21.“). fork := true sorgt dafür, dass sbt das Programm in einer eigenen JVM startet – JavaFX verträgt es schlecht, mehrfach in derselben JVM gestartet zu werden.
Das erste Fenster
import scalafx.application.JFXApp3
import scalafx.scene.Scene
import scalafx.scene.control.{Button, Label}
import scalafx.scene.layout.VBox
import scalafx.geometry.Insets
object Hallo extends JFXApp3:
override def start(): Unit =
val anzeige = new Label("Noch nicht geklickt")
stage = new JFXApp3.PrimaryStage:
title = "Hallo ScalaFX"
scene = new Scene(360, 180):
root = new VBox:
spacing = 12
padding = Insets(20)
children = Seq(
anzeige,
new Button("Klick mich"):
onAction = _ => anzeige.text = "Geklickt!"
)Der Aufbau folgt der JavaFX-Hierarchie: Eine Stage ist das Fenster, darin liegt eine Scene, deren root der oberste Knoten des Oberflächenbaums ist. onAction erwartet eine Funktion; der Unterstrich ignoriert das übergebene Ereignisobjekt.
Layouts
| Layout | Anordnung |
|---|---|
VBox / HBox | untereinander / nebeneinander |
BorderPane | oben, unten, links, rechts, Mitte |
GridPane | Raster mit Zeilen und Spalten |
StackPane | übereinander gestapelt, z. B. Text auf Bild |
FlowPane | fließend mit Umbruch |
Die Idee ist dieselbe wie bei den Panels in Swing: Layouts werden verschachtelt, bis die gewünschte Anordnung entsteht.
Properties und Bindings
Das Besondere an JavaFX sind beobachtbare Werte. In ScalaFX lassen sie sich mit wenigen Zeichen verknüpfen:
import scalafx.scene.control.{Slider, Label}
import scalafx.beans.binding.Bindings
val regler = new Slider(0, 100, 50)
val wert = new Label
wert.text <== Bindings.createStringBinding(
() => f"${regler.value()}%.0f Prozent",
regler.value
)Der Operator <== bindet eine Eigenschaft einseitig an eine andere: Bewegt jemand den Regler, ändert sich die Beschriftung von selbst. Mit <==> entsteht eine Bindung in beide Richtungen, etwa zwischen zwei Eingabefeldern. Code, der Oberflächen mühsam „von Hand“ aktualisiert, entfällt damit größtenteils.
Auch Bedingungen lassen sich binden:
knopf.disable <== eingabe.text.isEmptyDer Knopf ist nur aktiv, solange etwas eingegeben wurde.
Gestalten mit CSS
JavaFX-Oberflächen lassen sich mit einer eigenen CSS-Variante gestalten. Eigenschaften beginnen mit -fx-:
.root { -fx-font-size: 14px; -fx-background-color: #1a1d23; }
.button { -fx-background-color: #d8392a; -fx-text-fill: white; }
.label { -fx-text-fill: #ebe7de; }Eingebunden wird die Datei über die Szene: scene.stylesheets += getClass.getResource("/stil.css").toExternalForm. Einzelne Knoten lassen sich zusätzlich mit style = "-fx-font-weight: bold" gestalten.
Swing oder ScalaFX?
| Swing (scala-swing) | ScalaFX | |
|---|---|---|
| im JDK enthalten | ja | nein, Bibliothek nötig |
| Aussehen | klassisch, begrenzt anpassbar | modern, per CSS gestaltbar |
| Bindings | nein | ja |
| Grafik, Animation | einfach | umfangreich |
| Einsatz | Werkzeuge, Bestand | neue Desktop-Anwendungen |