Übungsaufgaben zu FXML, Layouts und CSS: eine Maske für die Mitfahrgesuche
https://bildung.social/@oerinformatik/
https://oer-informatik.de/javafx-fxml-layouts-css-uebungsaufgaben
JavaFX, FXML, Controller, fx:id, Scene Builder, GridPane, Layout-Container, JavaFX-CSS, Fehlersuche, Übungsaufgaben, Prüfungsvorbereitung
tl/dr; (ca. 64 min Lese- und Bearbeitungszeit): Übungen zu FXML, Layout-Containern und JavaFX-CSS: Du ordnest Anordnungen dem passenden Layout-Container zu, beschreibst das Gesuche-Fenster der Desktop-App als FXML-Datei, verbindest es mit einem Controller und einem Stylesheet und findest Fehler in einer FXML-Datei anhand der Meldungen [AI-Assisted]. (Zuletzt geändert am 11.11.2026)
Dieser Artikel ist Teil einer Artikelreihe über eine Desktop-App mit JavaFX: Übersicht / Kanban-Projektstart / Projekt anlegen / FXML, Layouts und CSS / Properties, Bindings und MVVM / Backend anbinden / TableView für Buchungen / Formulare und Dialoge / Anmeldung mit Keycloak / Verwaltung und Diagramme / GUI-Tests mit TestFX / Abnahmetest und Kanban-Metriken / Paketieren mit jpackage
Diese Übungsaufgaben gehören zum Artikel FXML, Layouts und CSS: Das Hauptfenster der Desktop-App gestalten. Sie spielen im Projekt Mitfahrlabor und führen den Strang der Mitfahrgesuche weiter: Für Ticket JFX-13 „Offene Gesuche an meinem Haltepunkt anzeigen“ gibt es seit den Übungen zum JavaFX-Projekt ein Fenster MitfahrgesucheApp mit einem Platzhalter, im Java-Code aufgebaut. Jetzt bekommt es eine Maske, mit der Fahrer*innen die Gesuche nach Haltepunkt, Richtung und Datum eingrenzen; die Daten selbst folgen später.
Hinweise zur Bearbeitung: Bis zur Teil-1-Prüfung der IT-Berufe solltest Du die Basiskompetenz beherrschen, also Aufgabe 1.1. Als FIA, FIDP oder FIDV musst Du zur Teil-2-Prüfung Aufgaben auf Kernkompetenz-Ebene lösen können, das sind Aufgabe 2.1 und Aufgabe 2.2. Von FIA wird zusätzlich erwartet, dass ihnen Aufgaben auf Profilkompetenz-Ebene (Aufgabe 3.1) keine Probleme bereiten. Als Startcode dient der Code-Stand src/03-fxml-layouts-css/mitfahrlabor-desktop aus dem Artikel; übernimm daraus Deine Klasse MitfahrgesucheApp aus den letzten Übungen oder lege sie neu an. Eine vollständige Beispiellösung der Aufgaben 2.1 und 2.2 mit Tests liegt unter src/03-fxml-layouts-css/uebung-mitfahrgesuche. Code-Aufgaben löst Du am besten am Rechner und prüfst sie mit gradlew test und gradlew run (bzw. mvnw test und mvnw javafx:run). Schreib Deine Lösung zuerst vollständig auf, bevor Du die Beispiellösung aufklappst.
Du möchtest eigene Aufgaben zum Üben von einem KI-Sprachmodell generieren lassen?
Kopiere den Text in ein KI-Sprachmodell Deiner Wahl und passe Kompetenzstufe, Anzahl, Bearbeitungszeit und Szenario bei Bedarf an. Wie die Aufgaben aufgebaut sind, beschreibt der Artikel Wie sind die Aufgaben aufgebaut?. Prüfe die Ergebnisse mit dem Lehrartikel: KI-Sprachmodelle machen Fehler.
Erstelle neue Übungsaufgaben zum Thema „FXML, Layouts und CSS: eine
Maske für die Mitfahrgesuche“.
Bauplan: Halte Dich an Aufbau, Kompetenzstufen, Operatoren,
Anforderungsbereiche, Punkte und Zeitschätzung, die im Artikel
https://oer-informatik.de/aufgaben-aufbau beschrieben sind.
Fachliche Grundlage:
- https://oer-informatik.de/javafx-fxml-layouts-css
- https://oer-informatik.de/szenario-mitfahrlabor
- https://oer-informatik.de/javafx-kanban-projektstart
- Stilbeispiel: https://oer-informatik.de/javafx-fxml-layouts-css-uebungsaufgaben
Die Aufgaben sollen Inhalte zu diesen Schlagwörtern abdecken:
- JavaFX
- FXML
- Controller
- fx:id
- Scene Builder
- GridPane
- Layout-Container
- JavaFX-CSS
- Fehlersuche
Kompetenzstufe: Kernkompetenz (alternativ: Basiskompetenz, Profilkompetenz, Expertise)
Anzahl: 1 Aufgabe mit Teilaufgaben
Bearbeitungszeit in Minuten ca.: <5 bis 30 min>
Szenario: eines der Szenarien aus dem Bauplan
Vorgehen:
1. Lies zuerst die verlinkten Artikel. Kannst Du keine Webseiten
abrufen, sag mir das, statt zu raten.
2. Steht bei einer Angabe noch ein Platzhalter in <…>, frag mich
zuerst danach. Richte Punkte und Zahl der Teilaufgaben nach der
Bearbeitungszeit (ca. 0,9 min je Punkt).
3. Gib je Aufgabe Titel mit Kompetenzstufe, Ausgangssituation und
Teilaufgaben mit Operator und Punktzahl aus, dazu die geschätzte
Bearbeitungszeit.
4. Gib die Beispiellösungen mit Punkteverteilung erst aus, wenn ich
danach frage.
Aufgabe 1.1: Layout-Container zuordnen (Basiskompetenz)
Lukas Hofmann aus dem Projektteam skizziert für die Desktop-App von Mitfahrlabor weitere Fenster und fragt, welcher Layout-Container jeweils passt.
- Ordne jeder Anordnung den passenden Container zu. Zur Auswahl stehen
BorderPane,HBox,VBox,GridPaneundStackPane; jeder Container wird genau einmal gebraucht. (5 Punkte)
| Nr. | Anordnung | Container |
|---|---|---|
| 1 | Die Buttons „Bestätigen“, „Ablehnen“ und „Schließen“ stehen nebeneinander am unteren Rand eines Dialogs. | |
| 2 | Ein Anmeldeformular: links die Beschriftungen „Benutzername“ und „Passwort“, rechts daneben bündig die Eingabefelder. | |
| 3 | Über der Liste der Buchungen liegt, solange sie lädt, ein halbtransparenter Hinweis „Wird geladen …“. | |
| 4 | Ein Fenster mit Menüleiste oben, Navigation links, Inhalt in der Mitte und Statuszeile unten. | |
| 5 | Eine Spalte mit Überschrift, darunter ein Suchfeld und darunter eine Liste, die mit dem Fenster in die Höhe wächst. |
- Gegeben ist dieser Ausschnitt einer FXML-Datei. Beschreibe, wie die vier Nodes im Fenster angeordnet sind, und skizziere die Anordnung. (3 Punkte)
<VBox spacing="8">
<Label text="Buchungen"/>
<HBox spacing="8">
<Button text="Bestätigen"/>
<Button text="Ablehnen"/>
</HBox>
<ListView fx:id="buchungsliste"/>
</VBox>- Im Fenster aus b) bleibt die Liste beim Vergrößern des Fensters gleich hoch, darunter entsteht eine leere Fläche. Nenne die Einstellung, mit der die Liste mitwächst, und gib an, an welchem Element sie steht. (2 Punkte)
- Je richtiger Zeile 1 Punkt:
| Nr. | Container | Begründung |
|---|---|---|
| 1 | HBox |
Kinder nebeneinander in einer Zeile |
| 2 | GridPane |
Raster: Beschriftungen in Spalte 0, Felder in Spalte 1, bündig |
| 3 | StackPane |
legt Kinder übereinander (Liste unten, Hinweis darüber) |
| 4 | BorderPane |
Bereiche top, left, center, bottom |
| 5 | VBox |
Kinder untereinander in einer Spalte |
- Die
VBoxstellt drei Kinder untereinander mit 8 Pixel Abstand (1 Punkt): oben das Label „Buchungen“, darunter eine Zeile, in der dieHBoxdie beiden Buttons „Bestätigen“ und „Ablehnen“ nebeneinander zeigt (1 Punkt), darunter die Liste (1 Punkt). Skizze:
+------------------------------+
| Buchungen |
| [Bestätigen] [Ablehnen] |
| +--------------------------+ |
| | buchungsliste | |
| +--------------------------+ |
+------------------------------+
VBox.vgrow="ALWAYS"(1 Punkt) am ElementListView, nicht an derVBox(1 Punkt). Im Java-Code:VBox.setVgrow(buchungsliste, Priority.ALWAYS).
Aufgabe 2.1: Die Gesuche-Maske in FXML (Kernkompetenz)
Fahrer*innen sollen im Gesuche-Fenster der Desktop-App von Mitfahrlabor einstellen können, welche Gesuche sie sehen wollen. Ben Richter wünscht sich das Fenster so:
- oben eine farbige Kopfzeile mit der Überschrift „Offene Mitfahrgesuche“ (Kennung
gesucheUeberschrift), - links eine Maske mit vier Zeilen: „Haltepunkt“ mit einer Auswahlliste (
ComboBox, KennunghaltepunktAuswahl), „Richtung“ mit zwei Optionsfeldern „zur Schule“ (zurSchule, vorausgewählt) und „nach Hause“ (nachHause), „Datum“ mit einem Datumsfeld (DatePicker, KennungdatumAuswahl) und darunter ein Button „Filtern“ (Kennungfiltern); die Maske selbst hat die KennunggesuchMaske, - rechts daneben die Überschrift „Gesuche“ und darunter eine Liste (Kennung
gesucheListe), die mit dem Fenster wächst, - unten eine Hinweiszeile (Kennung
gesuchHinweis) mit dem Text „Noch keine Mitfahrgesuche geladen.“
Die beiden Optionsfelder gehören zu einer Gruppe, damit immer nur eines gewählt ist. In FXML legst Du die Gruppe beim ersten Optionsfeld an und verweist beim zweiten darauf:
<RadioButton fx:id="zurSchule" text="zur Schule" selected="true">
<toggleGroup>
<ToggleGroup fx:id="richtung"/>
</toggleGroup>
</RadioButton>
<RadioButton fx:id="nachHause" text="nach Hause" toggleGroup="$richtung"/>Plane das Fenster: Nenne für den Wurzelknoten, die Kopfzeile, die Maske, den rechten Bereich und die Zeile mit den Optionsfeldern jeweils den Layout-Container und begründe die Wahl der Maske kurz. (4 Punkte)
Schreibe die Datei
gesuche.fxmlmit allen Importen, dem Controllerde.dbh.mitfahrlabor.desktop.GesucheControllerund den genannten Kennungen. Den Button verbindest Du mit der Methodefiltern. Lege die Datei an der richtigen Stelle im Projekt ab. (10 Punkte)Baue
MitfahrgesucheAppso um, dass siegesuche.fxmllädt und die Stylesheetsmitfahrlabor.cssundgesuche.cssan die Scene hängt (Fenstergröße 800 × 500). (4 Punkte)
- Je richtiger Container 0,5 Punkte, Begründung 1,5 Punkte (nachvollziehbar, auch andere sinnvolle Lösungen):
| Bereich | Container |
|---|---|
| Wurzelknoten | BorderPane (Bereiche top, left, center, bottom) |
| Kopfzeile | HBox |
| Maske | GridPane |
| rechter Bereich | VBox (Überschrift über Liste, Liste mit VBox.vgrow) |
| Optionsfelder | HBox (nebeneinander in Spalte 1 des GridPane) |
Begründung Maske: Beschriftungen und Eingabefelder stehen in zwei Spalten; im GridPane beginnen alle Felder an derselben Stelle, auch wenn die Beschriftungen unterschiedlich lang sind.
- Bewertung: Importe vollständig (1 Punkt), Wurzelelement mit Namensräumen und
fx:controller(1 Punkt), Kopfzeile (1 Punkt), GridPane mit Zeilen- und Spaltenangaben (2 Punkte), Optionsfelder mit gemeinsamer Gruppe (1 Punkt), DatePicker und Button mitonAction="#filtern"(1 Punkt), rechter Bereich mit wachsender Liste (1 Punkt), Hinweiszeile (1 Punkt), Ablage untersrc/main/resources/de/dbh/mitfahrlabor/desktop/gesuche.fxml(1 Punkt). Die Tastenkürzel (_Haltepunkt,labelFor) gehören zu Aufgabe 2.2 d.
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.control.DatePicker?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.control.RadioButton?>
<?import javafx.scene.control.ToggleGroup?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<BorderPane xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml"
fx:controller="de.dbh.mitfahrlabor.desktop.GesucheController"
styleClass="hauptfenster">
<top>
<HBox styleClass="kopfzeile" alignment="CENTER_LEFT">
<Label fx:id="gesucheUeberschrift" text="Offene Mitfahrgesuche" styleClass="app-titel"/>
</HBox>
</top>
<!-- links: Filtermaske als Formular in zwei Spalten -->
<left>
<GridPane fx:id="gesuchMaske" styleClass="bereich, maske" hgap="8" vgap="10">
<!-- erst das Feld, dann das Label: labelFor="$…" verweist nur auf schon geladene Elemente -->
<ComboBox fx:id="haltepunktAuswahl" prefWidth="220"
GridPane.columnIndex="1" GridPane.rowIndex="0"/>
<Label text="_Haltepunkt" mnemonicParsing="true" labelFor="$haltepunktAuswahl"
GridPane.columnIndex="0" GridPane.rowIndex="0"/>
<Label text="Richtung" GridPane.columnIndex="0" GridPane.rowIndex="1"/>
<HBox spacing="12" GridPane.columnIndex="1" GridPane.rowIndex="1">
<RadioButton fx:id="zurSchule" text="zur Schule" selected="true">
<toggleGroup>
<ToggleGroup fx:id="richtung"/>
</toggleGroup>
</RadioButton>
<RadioButton fx:id="nachHause" text="nach Hause" toggleGroup="$richtung"/>
</HBox>
<DatePicker fx:id="datumAuswahl" prefWidth="220"
GridPane.columnIndex="1" GridPane.rowIndex="2"/>
<Label text="_Datum" mnemonicParsing="true" labelFor="$datumAuswahl"
GridPane.columnIndex="0" GridPane.rowIndex="2"/>
<Button fx:id="filtern" text="_Filtern" mnemonicParsing="true" defaultButton="true"
onAction="#filtern" GridPane.columnIndex="1" GridPane.rowIndex="3"/>
</GridPane>
</left>
<!-- Mitte: Liste der Gesuche (Daten folgen später) -->
<center>
<VBox styleClass="bereich" spacing="8">
<Label text="Gesuche" styleClass="bereich-titel"/>
<ListView fx:id="gesucheListe" VBox.vgrow="ALWAYS"/>
</VBox>
</center>
<bottom>
<Label fx:id="gesuchHinweis" styleClass="statuszeile" maxWidth="Infinity"
text="Noch keine Mitfahrgesuche geladen."/>
</bottom>
</BorderPane>Mit dem Stylesheet aus Aufgabe 2.2 sieht das Fenster so aus:
- Bewertung: FXMLLoader mit
getResource("gesuche.fxml")(1 Punkt),load()als Wurzel der Scene (1 Punkt), beide Stylesheets mittoExternalForm()angehängt (1 Punkt),throws IOExceptionbzw. Behandlung der Ausnahme (1 Punkt).
@Override
public void start(Stage stage) throws IOException {
Parent wurzel = new FXMLLoader(
MitfahrgesucheApp.class.getResource("gesuche.fxml")).load();
Scene scene = new Scene(wurzel, 800, 500);
scene.getStylesheets().addAll(
MitfahrgesucheApp.class.getResource("mitfahrlabor.css").toExternalForm(),
MitfahrgesucheApp.class.getResource("gesuche.css").toExternalForm());
stage.setTitle(TITEL);
stage.setScene(scene);
stage.show();
}Aufgabe 2.2: Controller und Stylesheet für die Gesuche-Maske (Kernkompetenz)
Die Maske aus Aufgabe 2.1 soll jetzt reagieren. Solange das Backend noch nicht angebunden ist, zeigt „Filtern“ nur an, welche Auswahl getroffen wurde. Die Haltepunkte stehen vorerst fest im Code; es sind die sechs Haltepunkte aus den Beispieldaten des Backends: „Hauptbahnhof, ZOB Steig 3 (Gütersloh)“, „Park & Ride am Bahnhof (Herford)“, „Marktplatz (Halle (Westf.))“, „Busbahnhof (Bad Salzuflen)“, „Kirchplatz (Werther (Westf.))“ und „Bahnhof Brackwede (Bielefeld)“.
Schreibe die Klasse
GesucheControllermit den nötigen@FXML-Feldern und einer Methodeinitialize(), die die Auswahlliste mit den sechs Haltepunkten füllt. (4 Punkte)Ergänze die Methode
filtern(): (5 Punkte)
- Fehlen Haltepunkt oder Datum, zeigt die Hinweiszeile „Bitte Haltepunkt und Datum wählen.“ und bekommt zusätzlich die Style-Klasse
fehler(nur einmal, auch bei mehrfachem Klick). - Sonst zeigt sie z. B. „Filter: Busbahnhof (Bad Salzuflen), nach Hause, 22.10.2026“, und die Style-Klasse
fehlerwird entfernt.
Schreibe die Datei
gesuche.css: Die Maske bekommt einen hellen Hintergrund und eine feine Linie am rechten Rand, alle Beschriftungen der Maske sind fett, und eine Hinweiszeile mit der Style-Klassefehlererscheint mit hellrotem Hintergrund und dunkelroter Schrift. (4 Punkte)Ben arbeitet am liebsten mit der Tastatur. Erläutere, wie Alt+H direkt in die Auswahl der Haltepunkte springen kann, und warum dafür in der FXML-Datei die
ComboBoxvor ihrem Label stehen muss. (3 Punkte)
Bewertung: Felder mit
@FXMLund passenden Typen und Namen (2 Punkte; nur die Felder, die der Controller benutzt, sind nötig),initialize()mit@FXML(1 Punkt), Haltepunkte eingetragen (1 Punkt).Bewertung: Prüfung auf
nullfür beide Werte (1 Punkt), Fehlertext (1 Punkt), Style-Klasse ohne Doppelung hinzufügen bzw. entfernen (1 Punkt), Richtung aus dem Optionsfeld (1 Punkt), Datum formatiert (1 Punkt).
public class GesucheController {
@FXML private ComboBox<String> haltepunktAuswahl;
@FXML private RadioButton zurSchule;
@FXML private DatePicker datumAuswahl;
@FXML private Label gesuchHinweis;
@FXML
private void initialize() {
// Haltepunkte aus data.sql des Backends (lokal, bis die REST-API angebunden ist)
haltepunktAuswahl.getItems().setAll(
"Hauptbahnhof, ZOB Steig 3 (Gütersloh)",
"Park & Ride am Bahnhof (Herford)",
"Marktplatz (Halle (Westf.))",
"Busbahnhof (Bad Salzuflen)",
"Kirchplatz (Werther (Westf.))",
"Bahnhof Brackwede (Bielefeld)");
}
@FXML
private void filtern() {
if (haltepunktAuswahl.getValue() == null || datumAuswahl.getValue() == null) {
gesuchHinweis.setText("Bitte Haltepunkt und Datum wählen.");
if (!gesuchHinweis.getStyleClass().contains("fehler")) {
gesuchHinweis.getStyleClass().add("fehler");
}
return;
}
gesuchHinweis.getStyleClass().remove("fehler");
String richtung = zurSchule.isSelected() ? "zur Schule" : "nach Hause";
gesuchHinweis.setText("Filter: " + haltepunktAuswahl.getValue() + ", " + richtung + ", "
+ datumAuswahl.getValue().format(DateTimeFormatter.ofPattern("dd.MM.yyyy")));
}
}Der Test GesucheControllerTest in der Beispiellösung lädt die FXML-Datei, setzt Haltepunkt, Richtung und Datum, löst den Button mit fire() aus und prüft den Text und die Style-Klasse.
- Bewertung: Selektor
.maskemit Hintergrund und Rahmen nur rechts (1 Punkt), Nachfahren-Selektor.maske .label(1 Punkt), kombinierte Klassen.statuszeile.fehler(1 Punkt), durchgehend-fx--Eigenschaften (1 Punkt).
.maske {
-fx-background-color: #f7f9fc;
-fx-border-color: transparent #c8d3e0 transparent transparent;
}
.maske .label {
-fx-font-weight: bold;
}
.statuszeile.fehler {
-fx-background-color: #fde8e8;
-fx-text-fill: #9b1c1c;
}.statuszeile.fehler (ohne Leerzeichen) trifft nur Nodes, die beide Klassen haben, und ist spezifischer als .statuszeile aus mitfahrlabor.css; deshalb gewinnt der rote Hintergrund. Die Reihenfolge der vier Werte bei -fx-border-color ist oben, rechts, unten, links.
- Das Label bekommt den Text
_HaltepunktmitmnemonicParsing="true"; der Unterstrich macht H zum Kürzel (1 Punkt).labelFor="$haltepunktAuswahl"leitet das Kürzel an die ComboBox weiter (1 Punkt). Der Ausdruck$haltepunktAuswahlverweist auf ein Element, das der FXMLLoader schon erzeugt hat; steht die ComboBox erst hinter dem Label, ist der Verweis beim Lesen des Labels noch leer undlabelForbleibt ohne Meldungnull(1 Punkt). Die Position im Raster bestimmenGridPane.rowIndexundcolumnIndex, nicht die Reihenfolge in der Datei; deshalb darf die ComboBox vorne stehen.
Aufgabe 3.1: FXML-Fehler anhand der Meldungen finden (Profilkompetenz)
Oksana Melnyk hat das Gesuche-Fenster parallel zu Dir gebaut. Ihre Pipeline war grün, die Kollegin im Test hat die App mit gradlew run gestartet und das Ticket mit rotem Punkt zurückgegeben. Oksana hat danach die Meldungen nacheinander gesammelt; nach jeder Meldung wurde die Ursache behoben und neu gestartet. Auszüge aus ihren Dateien (Ausschnitte, die übrigen Teile entsprechen der Beispiellösung von Aufgabe 2.1 und 2.2):
module-info.java:
module de.dbh.mitfahrlabor.desktop {
requires javafx.controls;
requires javafx.fxml;
exports de.dbh.mitfahrlabor.desktop;
}gesuche.fxml (Ausschnitt):
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.control.RadioButton?>
<?import javafx.scene.control.ToggleGroup?>
<!-- ... Layout-Importe wie in der Beispiellösung ... -->
<DatePicker fx:id="datum" prefWidth="220"
GridPane.columnIndex="1" GridPane.rowIndex="2"/>
<Label text="_Datum" mnemonicParsing="true" labelFor="$datum"
GridPane.columnIndex="0" GridPane.rowIndex="2"/>
<Button fx:id="filtern" text="_Filtern" mnemonicParsing="true" defaultButton="true"
onAction="#suchen" GridPane.columnIndex="1" GridPane.rowIndex="3"/>gesuche.css (Ausschnitt):
.statuszeile.fehler {
background-color: #fde8e8;
-fx-text-fill: #9b1c1c;
}Der Controller entspricht der Beispiellösung von Aufgabe 2.2 (Feld @FXML private DatePicker datumAuswahl;, Methode @FXML private void filtern()).
Die gesammelten Meldungen (gekürzt, jeweils die letzte Zeile „Caused by“):
| Nr. | Wann | Meldung bzw. Beobachtung |
|---|---|---|
| M1 | Start mit gradlew run |
InaccessibleObjectException: Unable to make field private javafx.scene.control.ComboBox de.dbh.mitfahrlabor.desktop.GesucheController.haltepunktAuswahl accessible: module de.dbh.mitfahrlabor.desktop does not "opens de.dbh.mitfahrlabor.desktop" to module javafx.fxml |
| M2 | Start mit gradlew run |
LoadException: DatePicker is not a valid type. mit Verweis auf gesuche.fxml:44 |
| M3 | Start mit gradlew run |
LoadException: Error resolving onAction='#suchen', either the event handler is not in the Namespace or there is an error in the script. |
| M4 | Fenster offen, Haltepunkt gewählt, Klick auf „Filtern“ | NullPointerException: Cannot invoke "javafx.scene.control.DatePicker.getValue()" because "this.datumAuswahl" is null |
| M5 | Fenster offen, Klick auf „Filtern“ ohne Auswahl | Der Fehlertext erscheint in dunkelroter Schrift, der Hintergrund bleibt aber hellblau. |
Gib für jede Meldung M1 bis M5 die Ursache in Oksanas Dateien an und korrigiere sie. (10 Punkte)
Erkläre, warum M4 erst nach der Wahl eines Haltepunkts auftritt und nicht schon beim Klick auf „Filtern“ ohne Auswahl. (2 Punkte)
Die Pipeline führt die Tests
GesucheControllerTestaus der Beispiellösung von Aufgabe 2.2 aus. Beurteile für jede der fünf Ursachen, ob diese Tests sie gefunden hätten, und begründe für M1. Schlage eine Regel für das Kanban-Board vor, die solche Fehler künftig vor „Fertig“ abfängt. (6 Punkte)
- Je Meldung 1 Punkt für die Ursache, 1 Punkt für die Korrektur:
| Nr. | Ursache | Korrektur |
|---|---|---|
| M1 | In module-info.java fehlt opens; javafx.fxml darf die privaten @FXML-Felder nicht setzen |
opens de.dbh.mitfahrlabor.desktop to javafx.fxml; ergänzen |
| M2 | Import für DatePicker fehlt in gesuche.fxml |
<?import javafx.scene.control.DatePicker?> ergänzen |
| M3 | onAction="#suchen", im Controller heißt die Methode filtern |
onAction="#filtern" |
| M4 | fx:id="datum" passt nicht zum Feld datumAuswahl; das Feld bleibt null |
fx:id="datumAuswahl" und labelFor="$datumAuswahl" (oder Feld umbenennen) |
| M5 | background-color ohne Präfix; JavaFX ignoriert die Eigenschaft ohne Meldung |
-fx-background-color: #fde8e8; |
filtern()prüft zuersthaltepunktAuswahl.getValue() == null. Ist kein Haltepunkt gewählt, ist die Bedingung schon wahr, und der Operator||wertet den zweiten TeildatumAuswahl.getValue()gar nicht mehr aus (Kurzschlussauswertung, 1 Punkt). Erst wenn ein Haltepunkt gewählt ist, wird auf das leere FelddatumAuswahlzugegriffen und dieNullPointerExceptionausgelöst (1 Punkt).Bewertung: Einschätzung der fünf Ursachen (2,5 Punkte, je 0,5), Begründung zu M1 (1,5 Punkte), Regelvorschlag (2 Punkte).
- M2 und M3: gefunden, denn jeder Test lädt
gesuche.fxml, undload()bricht ab. - M4: gefunden, denn
lookup("#datumAuswahl")findet nichts, und der TestfilternZeigtAuswahlscheitert (der TestmaskeHatAlleFelderebenso). - M5: nicht gefunden, denn der Test prüft nur, ob die Style-Klasse
fehlergesetzt ist, nicht, wie das Stylesheet sie darstellt. - M1: nicht gefunden. Die Tests laufen auf dem Klassenpfad (wegen Monocle, bei Maven
useModulePath=false). Dort gibt es keine Modulgrenzen, diemodule-info.javawird nicht ausgewertet, und der FXMLLoader darf private Felder immer setzen. Erstgradlew runstartet auf dem Modulpfad.
Regel für das Board, z. B. in der Eintrittsregel der Spalte „Test“: Die prüfende Person startet die App einmal mit gradlew run und sieht sich die geänderten Fenster an, bevor das Ticket nach „Fertig“ wandert. Die Regeländerung wird mit Datum unter „Änderungen an den Regeln“ in board.md eingetragen. Ebenfalls sinnvoll: ein Smoke-Test, der die App als Prozess über den Modulpfad startet, oder eine Checkliste „neues Paket mit Controller: opens prüfen“.
Links und weitere Informationen
zum Artikel: FXML, Layouts und CSS: Das Hauptfenster der Desktop-App gestalten
zum Board: Kanban-Projektstart für die Desktop-App
als Nachschlagewerk: JavaFX CSS Reference Guide
für den Einstieg: Szenario Mitfahrlabor mit Personas und Regeln
Hinweis zur Nachnutzung als Open Educational Resource (OER)
Dieser Artikel und seine Texte, Bilder, Grafiken, Code und sonstiger Inhalt sind - sofern nicht anders angegeben - lizenziert unter CC BY 4.0. Nennung gemäß TULLU-Regel bitte wie folgt: “Übungsaufgaben zu FXML, Layouts und CSS: eine Maske für die Mitfahrgesuche” von oer-informatik.de (H. Stein), Lizenz: CC BY 4.0. Der Artikel wurde unter https://oer-informatik.de/javafx-fxml-layouts-css-uebungsaufgaben veröffentlicht, die Quelltexte sind in weiterverarbeitbarer Form verfügbar im Repository unter https://gitlab.com/oer-informatik/javafx/javafx-einstieg. Erstellt mit KI-Assistenz; von mir umfassend redaktionell überarbeitet, geprüft und freigegeben. Stand: 11.11.2026.
[Kommentare zum Artikel lesen, schreiben] / [Artikel teilen] / [gitlab-Issue zum Artikel schreiben]
