Labor 2023-05-10 Bilder-Admin
in Arbeit ...
1. Allgemeines
Erstelle eine Bild-Betrachter-App, die durch eine kommentierte Sammlung von Bildern "blättern" kann.
Die Bilder haben Dateiname, Kurzbeschreibung, Datum, die Charakterisierung Landschaft/Personen/Weiteres ('L'
, 'P'
, 'W'
) o.ä. und 0 … 5 Freitext-Merkmale.
Eine mögliche 0_sammlung.csv
-Datei (das 0_
am Anfang ermöglicht bei alphabetischer Sortierung die CSV-Datei ganz oben anzuzeigen):
bild1.jpg;Die Beschreibung;2023-05-10;L;Schön;Österreich;Berge;Winter;Abend bild2.png;Info dazu;1999-01-03;W weihnachtsfoto1.png;wir alle;2022-12-24;P;Weihnacht;Familie
Eine Sammlung besteht aus einem Verzeichnis, das die Bilder und eine CSV-Datei 0_sammlung.csv enthält. Der im dafür vorhandenen TextField
vorgeschlagene Verzeichnis-Pfad kann durch eine System-Property festgelegt werden: In der IntelliJ-Run-Configuration mit "Modify options", dort "Add VM options" festgelegt werden: -Dsammlung.pfad=C:/der/Pfad/zur/Sammlung
.
2. Der View
Links (z.B. im BorderPane-Left-Bereich) wird das Bild angezeigt, wenn es fehlt, ein Dummy-Bild.
Der Benutzer kann max. 5 Merkmale in jeweils eigenen Textfeldern eingeben. Zur Erstellung eines solchen Textfeldes gibt es einen Button
mit Beschriftung "Neues Merkmal". Damit wird das schon vorhandene, unsichtbare (theNode.setVisible(false)
, theNode.isVisible()
) sichtbar gesetzt. Leere Merkmals-Felder werden bei Neu-Anzeige nicht dargestellt.
Eine CheckBox "Edit-Mode" ermöglicht/verhindert Bearbeitung.
Ein Screenshot der Oberfläche:

Zur Beschränkung der Komplexität ist das Hinzufügen neuer und Löschen vorhandener Bilder nicht zu implementieren.
Lediglich das Ändern von Daten vorhandener Bilder ist umzusetzen.
Im View ist die wichtigste (vielleicht einzige) Klasse GuiRoot
, in der die Container-Struktur und die statischen Elemente wie TextFields, Buttons, Labels, der ImageView aufgebaut wird.
Alle UI-Elemente, auf deren Werte zugegriffen werden muss oder die disabled/enabled oder visible/invisible gemacht werden müssen, sind als Instanzvariable auszuführen und es ist ein Getter zu erstellen (kein Setter, die UI-Elemente selbst sind unveränderlich, lediglich ihr Zustand kann geändert werden).
"Intelligenz" (Event-Handling, Listeners, etc.) wird im Controller hinzugefügt (den Aufruf von Handlern etc. könnte auch im View erfolgen, im Controller ist es etwas einfacher).
Der View hat KEINE AHNUNG vom Model – das kennt nur der Controller!
3. Das Model
Das Model besteht aus 2 Klassen: BildAdmEngine
und Bild
:
Hinweise:
-
Dateiname, Art und Merkmale dürfen nicht null und nicht 'blank' sein (
!txt.isBlank()
) -
Im Model führt jeder Fehler zu einer checked Exception, damit im View eine Meldung in der Statusleiste angezeigt werden kann.
5. Die Applikationsklasse
Hier ein Vorschlag dafür:
package my.jfxapp.lab15rx;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;
import my.jfxapp.lab15rx.control.GuiRootController;
import my.jfxapp.lab15rx.model.BildAdmEngine;
import my.jfxapp.lab15rx.view.GuiRoot;
import java.net.URL;
import java.util.logging.Logger;
public class JfxApp extends Application {
// See comments in file 'logging.properties' how to activate the own logging.properties
private static final Class<?> CL = java.lang.invoke.MethodHandles.lookup().lookupClass();
private static final String CLN = CL.getSimpleName();
private static final Logger LOG = Logger.getLogger(CL.getName());
// effectively final Singleton (only 1 instance) -> static var convenient:
private static JfxApp appObj = null;
private GuiRoot root;
private GuiRootController guiRootController;
private BildAdmEngine engine;
public static JfxApp obj() {
return appObj; // assigned best within init() - first instance method knowing 'this'
}
public static void main(String[] args) {
LOG.entering(CLN, "main", args);
launch(args);
LOG.exiting(CLN, "main");
}
@Override
public void init() throws Exception {
LOG.entering(CLN, "init");
JfxApp.appObj = this;
super.init();
engine = new BildAdmEngine();
guiRootController = new GuiRootController(engine);
// guiRoot has to be set within start(...) - we need all the GUI functionalities
}
@Override
public void stop() throws Exception {
LOG.entering(CLN, "stop");
//TODO: everything needed
super.stop();
}
@Override
public void start(Stage primStage) throws Exception {
LOG.entering(CLN, "start", primStage);
root = new GuiRoot().initGui();
guiRootController.setRoot(root);
primStage.setScene(setupScene(root, "application.css"));
primStage.show();
LOG.exiting(CLN, "start");
}
public Scene setupScene(GuiRoot root, String cssRscPath) { // ...Rsc...: Resources
Scene scene = new Scene(root);
if (cssRscPath != null) {
URL cssUrl = getClass().getResource(cssRscPath); // "application.css"
String cssLink = cssUrl.toExternalForm(); // equivalent: cssUrl.toString();
scene.getStylesheets().add(cssLink);
System.out.format("CSS-File URL is '%s'%n", cssLink);
}
return scene;
}
public GuiRoot getRoot() {
return root;
}
// primary stage and scene reachable from guiBase/root: root.getScene().getWindow()
}