First GUI with Metadata dialog created

This commit is contained in:
naumueller 2025-10-19 15:37:07 +02:00
commit afe9208c71
11 changed files with 677 additions and 0 deletions

40
nbactions.xml Normal file
View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<actions>
<action>
<actionName>run</actionName>
<packagings>
<packaging>jar</packaging>
</packagings>
<goals>
<goal>clean</goal>
<goal>javafx:run</goal>
</goals>
</action>
<action>
<actionName>debug</actionName>
<goals>
<goal>clean</goal>
<goal>javafx:run@ide-debug</goal>
</goals>
<properties>
<jpda.listen>true</jpda.listen>
</properties>
</action>
<action>
<actionName>profile</actionName>
<goals>
<goal>clean</goal>
<goal>javafx:run@ide-profile</goal>
</goals>
</action>
<action>
<actionName>CUSTOM-jlink</actionName>
<displayName>jlink</displayName>
<goals>
<goal>clean</goal>
<!-- compile not needed with javafx-maven-plugin v0.0.5 -->
<goal>compile</goal>
<goal>javafx:jlink</goal>
</goals>
</action>
</actions>

89
pom.xml Normal file
View File

@ -0,0 +1,89 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>efi.projekt</groupId>
<artifactId>Gesundheitsassistent</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>13</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>13</version>
</dependency>
<dependency>
<groupId>io.github.mkpaz</groupId>
<artifactId>atlantafx-base</artifactId>
<version>2.1.0</version>
<type>jar</type>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<release>11</release>
</configuration>
</plugin>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.4</version>
<configuration>
<mainClass>efi.projekt.gesundheitsassistent.FxStart</mainClass>
</configuration>
<executions>
<execution>
<!-- Default configuration for running -->
<!-- Usage: mvn clean javafx:run -->
<id>default-cli</id>
</execution>
<execution>
<!-- Configuration for manual attach debugging -->
<!-- Usage: mvn clean javafx:run@debug -->
<id>debug</id>
<configuration>
<options>
<option>-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=localhost:8000</option>
</options>
</configuration>
</execution>
<execution>
<!-- Configuration for automatic IDE debugging -->
<id>ide-debug</id>
<configuration>
<options>
<option>-agentlib:jdwp=transport=dt_socket,server=n,address=${jpda.address}</option>
</options>
</configuration>
</execution>
<execution>
<!-- Configuration for automatic IDE profiling -->
<id>ide-profile</id>
<configuration>
<options>
<option>${profiler.jvmargs.arg1}</option>
<option>${profiler.jvmargs.arg2}</option>
<option>${profiler.jvmargs.arg3}</option>
<option>${profiler.jvmargs.arg4}</option>
<option>${profiler.jvmargs.arg5}</option>
</options>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,73 @@
package efi.projekt.gesundheitsassistent;
import atlantafx.base.theme.NordDark;
import efi.projekt.gesundheitsassistent.controller.MetadataDialogController;
import efi.projekt.gesundheitsassistent.model.Metadata;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Modality;
import javafx.stage.Stage;
import java.io.IOException;
public class FxStart extends Application {
private static Scene scene;
private Metadata metadata; // das zentrale Model
@Override
public void start(Stage primaryStage) throws IOException {
// 1 Metadata Model erzeugen
metadata = new Metadata();
// 2 Metadata Dialog laden
FXMLLoader dialogLoader = new FXMLLoader(getClass()
.getResource("/efi/projekt/gesundheitsassistent/view/MetadataDialog.fxml"));
Parent dialogRoot = dialogLoader.load();
// Controller bekommen und Model übergeben
MetadataDialogController dialogController = dialogLoader.getController();
dialogController.setMetadata(metadata);
// 3 Dialog Stage erzeugen
Stage dialogStage = new Stage();
dialogStage.setTitle("Metadaten eingeben");
dialogStage.initModality(Modality.APPLICATION_MODAL); // blockiert Hauptfenster
dialogStage.setScene(new Scene(dialogRoot));
dialogStage.showAndWait(); // wartet bis Dialog geschlossen wird
// 4 Hauptfenster laden
FXMLLoader mainLoader = new FXMLLoader(getClass()
.getResource("/efi/projekt/gesundheitsassistent/view/FxView.fxml"));
Parent mainRoot = mainLoader.load();
scene = new Scene(mainRoot, 1280, 720);
Application.setUserAgentStylesheet(new NordDark().getUserAgentStylesheet());
primaryStage.setTitle("Virtueller Gesundheitsassistent");
primaryStage.setScene(scene);
primaryStage.show();
}
static void setRoot(String fxml) throws IOException {
scene.setRoot(loadFXML(fxml));
}
private static Parent loadFXML(String fxml) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(
FxStart.class.getResource("/efi/projekt/gesundheitsassistent/view/" + fxml + ".fxml")
);
return fxmlLoader.load();
}
public static void main(String[] args) {
launch();
}
public Metadata getMetadata() {
return metadata;
}
}

View File

@ -0,0 +1,48 @@
/*
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
* Click nbfs://nbhost/SystemFileSystem/Templates/javafx/FXMLController.java to edit this template
*/
package efi.projekt.gesundheitsassistent.controller;
import efi.projekt.gesundheitsassistent.model.FxModel;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
/**
* FXML Controller class
*
* @author aumni
*/
public class FxViewController implements Initializable {
private FxModel model;
@FXML
private Button exitButton;
/**
* Initializes the controller class.
*/
@Override
public void initialize(URL url, ResourceBundle rb) {
}
@FXML
private void handleExit() {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION, "Programm wirklich beenden?");
alert.showAndWait()
.filter(response -> response == ButtonType.OK)
.ifPresent(response -> System.exit(0));
}
public void setModel(FxModel model) {
this.model = model;
}
}

View File

@ -0,0 +1,76 @@
/*
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
*/
package efi.projekt.gesundheitsassistent.controller;
import efi.projekt.gesundheitsassistent.model.Metadata;
import javafx.fxml.FXML;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
/**
*
* @author aumni
*/
public class MetadataDialogController {
@FXML
private TextField nameField;
@FXML
private TextField ageField;
@FXML
private ChoiceBox<String> genderChoiceBox;
@FXML
private TextField heightField;
@FXML
private TextField weightField;
private Metadata metadata;
public void initialize() {
// ChoiceBox füllen
genderChoiceBox.getItems().addAll("Männlich", "Weiblich", "Divers");
genderChoiceBox.setValue("Männlich"); // default
}
public void setMetadata(Metadata metadata) {
this.metadata = metadata;
bindFields();
}
private void bindFields() {
// Bidirektionales Binding zwischen Model und UI
nameField.textProperty().bindBidirectional(metadata.nameProperty());
ageField.textProperty().bindBidirectional(metadata.ageProperty(), new javafx.util.converter.NumberStringConverter());
genderChoiceBox.valueProperty().bindBidirectional(metadata.genderProperty());
heightField.textProperty().bindBidirectional(metadata.heightProperty(), new javafx.util.converter.NumberStringConverter());
weightField.textProperty().bindBidirectional(metadata.weightProperty(), new javafx.util.converter.NumberStringConverter());
}
@FXML
private void handleOk() {
try {
metadata.validate();
// Dialog schließen
Stage stage = (Stage) nameField.getScene().getWindow();
stage.close();
} catch (IllegalArgumentException e) {
Alert alert = new Alert(Alert.AlertType.ERROR, e.getMessage(), ButtonType.OK);
alert.showAndWait();
}
}
@FXML
private void handleCancel() {
Stage stage = (Stage) nameField.getScene().getWindow();
stage.close();
}
}

View File

@ -0,0 +1,37 @@
/*
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
*/
package efi.projekt.gesundheitsassistent.model;
import java.io.Serializable;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
/**
*
* @author aumni
*/
/**
* Superklasse für alle Modelle
*/
public class FxModel implements Serializable {
private final StringProperty id = new SimpleStringProperty(this, "id");
public FxModel() {}
public FxModel(String id) {
this.id.set(id);
}
public StringProperty idProperty() { return id; }
public String getId() { return id.get(); }
public void setId(String id) { this.id.set(id); }
public void validate() throws IllegalArgumentException {
// Subklassen können überschreiben
}
}

View File

@ -0,0 +1,100 @@
/*
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
*/
package efi.projekt.gesundheitsassistent.model;
import javafx.beans.property.*;
/**
*
* @author aumni
*/
public class Metadata extends FxModel {
private StringProperty name = new SimpleStringProperty(this, "name");
private IntegerProperty age = new SimpleIntegerProperty(this, "age");
private StringProperty gender = new SimpleStringProperty(this, "gender");
private DoubleProperty height = new SimpleDoubleProperty(this, "height"); //in cm
private DoubleProperty weight = new SimpleDoubleProperty(this, "weight"); //in kg
public Metadata() {};
public Metadata(String name, int age, String gender, double height, double weight) {
this.name.set(name);
this.age.set(age);
this.gender.set(gender);
this.height.set(height);
this.weight.set(weight);
}
// Properties
public StringProperty nameProperty() {
return name;
}
public IntegerProperty ageProperty() {
return age;
}
public StringProperty genderProperty() {
return gender;
}
public DoubleProperty heightProperty() {
return height;
}
public DoubleProperty weightProperty() {
return weight;
}
//Getter & Setter
public String getName() {
return name.get();
}
public void setName(String name) {
this.name.set(name);
}
public int getAge() {
return age.get();
}
public void setAge(int age) {
this.age.set(age);
}
public String getGender() {
return gender.get();
}
public void setGender(String gender) {
this.gender.set(gender);
}
public double getHeight() {
return height.get();
}
public void setHeight(double height) {
this.height.set(height);
}
public double getWeight() {
return weight.get();
}
public void setWeight(double weight) {
this.weight.set(weight);
}
@Override
public void validate() {
if (getName() == null || getName().isBlank()) throw new IllegalArgumentException("Name darf nicht leer sein") ;
if (getAge() < 0) throw new IllegalArgumentException("Alter darf nicht negativ sein");
if (getGender() == null || getGender().isBlank()) throw new IllegalArgumentException("Geschlecht muss gesetzt sein");
if (getHeight() <= 0) throw new IllegalArgumentException("Größe muss größer 0 sein");
if (getWeight() <= 0) throw new IllegalArgumentException("Gewicht muss größer 0 sein");
}
}

View File

@ -0,0 +1,13 @@
module efi.projekt.gesundheitsassistent {
requires javafx.controls;
requires javafx.fxml;
requires java.base;
requires atlantafx.base;
opens efi.projekt.gesundheitsassistent to javafx.fxml;
opens efi.projekt.gesundheitsassistent.controller to javafx.fxml;
exports efi.projekt.gesundheitsassistent;
exports efi.projekt.gesundheitsassistent.controller;
}

View File

@ -0,0 +1,93 @@
/*
* Empty Stylesheet file.
*/
.mainFxmlClass {
}
/* =========================================================
Virtueller Gesundheitsassistent - Fahrzeug UI Design
========================================================= */
.root {
-fx-font-family: "Segoe UI", "Roboto", sans-serif;
-fx-background-color: linear-gradient(to bottom, #0f2027, #203a43, #2c5364);
-fx-text-fill: #e0e0e0;
}
/* -------------------- Überschriften & Text -------------------- */
.label {
-fx-text-fill: #ffffff;
-fx-font-size: 16px;
}
.title-label {
-fx-font-size: 22px;
-fx-font-weight: bold;
}
/* -------------------- Buttons -------------------- */
.button {
-fx-background-color: linear-gradient(to bottom, #00b4db, #0083b0);
-fx-text-fill: white;
-fx-font-size: 16px;
-fx-background-radius: 10;
-fx-padding: 8 20;
}
.button:hover {
-fx-background-color: linear-gradient(to bottom, #00d2ff, #3a7bd5);
}
/* -------------------- Panels -------------------- */
.titled-pane {
-fx-background-color: #1b2838;
-fx-text-fill: #ffffff;
}
.titled-pane > .title {
-fx-background-color: #273b4a;
-fx-padding: 10;
}
.titled-pane > .content {
-fx-background-color: #1f2f3a;
}
/* -------------------- Charts -------------------- */
.chart {
-fx-background-color: transparent;
}
.chart-plot-background {
-fx-background-color: rgba(255, 255, 255, 0.05);
-fx-border-color: #00b4db;
-fx-border-radius: 8;
}
.axis {
-fx-tick-label-fill: #cccccc;
}
.axis-label {
-fx-text-fill: #ffffff;
}
/* -------------------- Avatar Container -------------------- */
#avatarContainer {
-fx-background-color: rgba(0, 0, 0, 0.3);
-fx-border-color: #00b4db;
-fx-border-width: 2;
-fx-border-radius: 12;
}
/* -------------------- Scrollbar -------------------- */
.scroll-bar:horizontal, .scroll-bar:vertical {
-fx-background-color: transparent;
}
.scroll-bar .thumb {
-fx-background-color: #00b4db;
-fx-background-radius: 10;
}

View File

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TitledPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>
<BorderPane prefHeight="720" prefWidth="1280" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="efi.projekt.gesundheitsassistent.controller.FxViewController">
<!-- ========= OBERER BEREICH ========= -->
<top>
<HBox alignment="CENTER_LEFT" spacing="20">
<padding>
<Insets bottom="15" left="15" right="15" top="15" />
</padding>
<Label text="Virtueller Gesundheitsassistent" />
<Button text="Einstellungen" />
</HBox>
</top>
<!-- ========= MITTLERER BEREICH ========= -->
<center>
<HBox spacing="20">
<padding>
<Insets bottom="15" left="15" right="15" top="15" />
</padding>
<!-- Linke Seite: Gesundheitsdaten -->
<VBox alignment="CENTER" spacing="15" HBox.hgrow="ALWAYS">
<TitledPane text="Gesundheitsdaten">
<content>
<VBox spacing="10">
<padding>
<Insets bottom="10" left="10" right="10" top="10" />
</padding>
<Label text="Herzfrequenz: 72 bpm" />
<Label text="Temperatur: 36.8 °C" />
<Label text="Stress-Level: Niedrig" />
</VBox>
</content>
</TitledPane>
</VBox>
<!-- Rechte Seite: Avatar -->
<VBox alignment="CENTER" spacing="15" HBox.hgrow="ALWAYS">
<TitledPane text="Avatar">
<content>
<StackPane fx:id="avatarContainer" alignment="CENTER" prefHeight="400" prefWidth="400">
<Label text="3D-Avatar wird geladen..." textFill="white" />
</StackPane>
</content>
</TitledPane>
</VBox>
</HBox>
</center>
<!-- ========= UNTERER BEREICH ========= -->
<bottom>
<HBox alignment="CENTER_RIGHT">
<padding>
<Insets bottom="15" left="15" right="15" top="15" />
</padding>
<Button onMouseClicked="#handleExit" text="Beenden" />
</HBox>
</bottom>
</BorderPane>

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.geometry.Insets?>
<VBox xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="efi.projekt.gesundheitsassistent.controller.MetadataDialogController"
spacing="10" alignment="CENTER">
<padding>
<Insets bottom="15" left="15" right="15" top="15" />
</padding>
<Label text="Bitte Metadaten eingeben" styleClass="dialog-title"/>
<GridPane hgap="10" vgap="10">
<Label text="Name:" GridPane.rowIndex="0" GridPane.columnIndex="0"/>
<TextField fx:id="nameField" GridPane.rowIndex="0" GridPane.columnIndex="1"/>
<Label text="Alter:" GridPane.rowIndex="1" GridPane.columnIndex="0"/>
<TextField fx:id="ageField" GridPane.rowIndex="1" GridPane.columnIndex="1"/>
<Label text="Geschlecht:" GridPane.rowIndex="2" GridPane.columnIndex="0"/>
<ChoiceBox fx:id="genderChoiceBox" GridPane.rowIndex="2" GridPane.columnIndex="1"/>
<Label text="Größe (cm):" GridPane.rowIndex="3" GridPane.columnIndex="0"/>
<TextField fx:id="heightField" GridPane.rowIndex="3" GridPane.columnIndex="1"/>
<Label text="Gewicht (kg):" GridPane.rowIndex="4" GridPane.columnIndex="0"/>
<TextField fx:id="weightField" GridPane.rowIndex="4" GridPane.columnIndex="1"/>
</GridPane>
<HBox spacing="10" alignment="CENTER_RIGHT">
<Button text="OK" onAction="#handleOk"/>
<Button text="Abbrechen" onAction="#handleCancel"/>
</HBox>
</VBox>