Compare commits

...

4 Commits

Author SHA1 Message Date
naumueller
95ecc48dcd Sidebar added 2025-11-02 19:10:58 +01:00
naumueller
1eb9ee4624 Comments and UI Logik added 2025-11-02 19:10:32 +01:00
naumueller
e4276d6cca showDashboard() function added 2025-11-02 19:09:58 +01:00
naumueller
1bf4594a93 Heartrate Simulator with visuals added 2025-11-02 19:09:09 +01:00
8 changed files with 236 additions and 15 deletions

View File

@ -85,4 +85,18 @@ public class FxViewController implements Initializable {
dialogStage.setScene(new Scene(dialogRoot));
dialogStage.showAndWait();
}
@FXML
private void showDashboard() throws IOException {
// Dialog
FXMLLoader loader = new FXMLLoader(getClass()
.getResource("/efi/projekt/gesundheitsassistent/view/HeartRateDashboard.fxml"));
Parent dialogRoot = loader.load();
// Dialog Stage erzeugen
Stage dialogStage = new Stage();
dialogStage.initModality(Modality.APPLICATION_MODAL);
dialogStage.setScene(new Scene(dialogRoot));
dialogStage.showAndWait();
}
}

View File

@ -0,0 +1,38 @@
/*
* 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.viewmodel.HeartRateViewModel;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.chart.LineChart;
/**
* FXML Controller class
*
* @author naumueller
*/
public class HeartRateController implements Initializable {
@FXML private LineChart<String, Number> heartRateChart;
private HeartRateViewModel viewModel;
/**
* Initializes the controller class.
*/
@Override
public void initialize(URL url, ResourceBundle rb) {
viewModel = new HeartRateViewModel();
}
@FXML
private void startSimulation() {
heartRateChart.getData().add(viewModel.getHeartRateSeries());
}
}

View File

@ -0,0 +1,46 @@
/*
* 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.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
*
* @author naumueller
*/
public class HeartRate {
private List<Integer> heartRateData = new ArrayList<>();
private int time = 0;
private Random random = new Random();
public HeartRate() {}
/** Neue Herzfrequenz simulieren */
public int simulateHeartRate() {
int base = 70;
int fluctuation = random.nextInt(30) - 10; // -10 bis +20
int bpm = base + fluctuation;
addData(bpm);
return bpm;
}
private void addData(int bpm) {
heartRateData.add(bpm);
time++;
if (heartRateData.size() > 60) {
heartRateData.remove(0); // nur letzte 60 Werte behalten
}
}
public List<Integer> getHeartRateData() {
return heartRateData;
}
public int getTime() {
return time;
}
}

View File

@ -89,7 +89,7 @@ public class MqttJavaClient implements MqttCallback {
System.out.println(" Inhalt: " + new String(message.getPayload()));
System.out.println(" QoS: " + message.getQos());
Consumer<String> listener = topicListeners.get(topic);
Consumer<String> listener = topicListeners.get(topic); // Consumer<String> aus HashMap holen
if (listener != null) {
listener.accept(payload);
}

View File

@ -16,24 +16,27 @@ import javafx.beans.property.StringProperty;
* @author naumueller
*/
public class FxViewModel {
private final FxModel model;
private Map<String, StringProperty> topicMessages = new HashMap<>();
private final StringProperty incomingMessage = new SimpleStringProperty("");
private final StringProperty outgoingMessage = new SimpleStringProperty("");
private final StringProperty messageToSend = new SimpleStringProperty("");
public FxViewModel(FxModel model) {
this.model = model;
subscribeTopic("Text");
subscribeTopic("Temperatur");
}
public void subscribeTopic(String topic) {
model.getMqttClient().addTopicListeners(topic, msg -> {
Platform.runLater(() -> getTopicProperty(topic).set(msg));
model.getMqttClient().addTopicListeners(topic, msg -> { // Consumer<String> mit Lambda-Funktion (wird ausgeführt, wenn message für topic ankommt)
Platform.runLater(() -> {
getTopicProperty(topic).set(msg); // Richtige Property für topic aus HashMap holen und Message anzeigen.
incomingMessage.set(msg);
});
});
}

View File

@ -0,0 +1,48 @@
/*
* 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.viewmodel;
import efi.projekt.gesundheitsassistent.model.HeartRate;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import javafx.application.Platform;
import javafx.scene.chart.XYChart;
/**
*
* @author naumueller
*/
public class HeartRateViewModel {
private HeartRate heartRate;
private XYChart.Series<String, Number> heartRateSeries = new XYChart.Series<>();
private Timer timer = new Timer(true);
public HeartRateViewModel() {
this.heartRate = new HeartRate();
heartRateSeries.setName("Herzfrequenz");
startSimulation();
}
public XYChart.Series<String, Number> getHeartRateSeries() { return heartRateSeries; }
private void startSimulation() {
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
int bpm = heartRate.simulateHeartRate();
int time = heartRate.getTime();
Platform.runLater(() -> addHeartRateData(time, bpm));
}
}, 0, 1000);
}
private void addHeartRateData(int time, int bpm) {
heartRateSeries.getData().add(new XYChart.Data<>(String.valueOf(time),bpm));
if (heartRateSeries.getData().size() > 60) {
heartRateSeries.getData().remove(0);
}
}
}

View File

@ -3,6 +3,9 @@
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Menu?>
<?import javafx.scene.control.MenuBar?>
<?import javafx.scene.control.MenuItem?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.control.TitledPane?>
<?import javafx.scene.image.Image?>
@ -20,8 +23,27 @@
<padding>
<Insets bottom="15" left="15" right="15" top="15" />
</padding>
<Label text="Virtueller Gesundheitsassistent" />
<Button onMouseClicked="#handleOptions" text="Einstellungen" />
<children>
<MenuBar prefHeight="25.0" prefWidth="1258.0">
<menus>
<Menu mnemonicParsing="false" text="File">
<items>
<MenuItem mnemonicParsing="false" text="Close" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="Edit">
<items>
<MenuItem mnemonicParsing="false" text="Delete" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="Help">
<items>
<MenuItem mnemonicParsing="false" text="About" />
</items>
</Menu>
</menus>
</MenuBar>
</children>
</HBox>
</top>
@ -89,7 +111,7 @@
<!-- Rechte Seite: Avatar -->
<VBox alignment="CENTER" spacing="15" HBox.hgrow="ALWAYS">
<TitledPane text="Avatar">
<TitledPane>
<content>
<StackPane fx:id="avatarContainer" alignment="CENTER" prefHeight="400" prefWidth="400">
<HBox alignment="CENTER" spacing="10">
@ -111,15 +133,36 @@
<!-- ========= UNTERER BEREICH ========= -->
<bottom>
<HBox alignment="CENTER_RIGHT">
<HBox alignment="CENTER_RIGHT" spacing="10.0">
<padding>
<Insets bottom="15" left="15" right="15" top="15" />
</padding>
<Button fx:id="sendButton" mnemonicParsing="false" onMouseClicked="#handleSendMessage" text="Send message" />
<TextField fx:id="messageInputField" />
<TextField fx:id="messageOutputField" editable="false" />
<Button fx:id="sendButton" mnemonicParsing="false" onMouseClicked="#handleSendMessage" text="Send message">
<HBox.margin>
<Insets />
</HBox.margin></Button>
<TextField fx:id="messageInputField">
<HBox.margin>
<Insets right="20.0" />
</HBox.margin></TextField>
<TextField fx:id="messageOutputField" editable="false">
<HBox.margin>
<Insets left="20.0" />
</HBox.margin></TextField>
<Button fx:id="exitButton" onMouseClicked="#handleExit" text="Beenden" />
</HBox>
</bottom>
<left>
<VBox prefHeight="200.0" prefWidth="186.0" BorderPane.alignment="CENTER">
<children>
<Button mnemonicParsing="false" onMouseClicked="#showDashboard" prefHeight="50.0" prefWidth="200.0" text="Gesundheitsdaten" />
<Button mnemonicParsing="false" prefHeight="50.0" prefWidth="200.0" text="Avatar" />
<Button mnemonicParsing="false" prefHeight="50.0" prefWidth="200.0" text="Einstellungen" />
</children>
<BorderPane.margin>
<Insets left="15.0" />
</BorderPane.margin>
</VBox>
</left>
</BorderPane>

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.chart.CategoryAxis?>
<?import javafx.scene.chart.LineChart?>
<?import javafx.scene.chart.NumberAxis?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.VBox?>
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" spacing="10.0" fx:controller="efi.projekt.gesundheitsassistent.controller.HeartRateController" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Label text="Herzfrequenz Dashboard">
<VBox.margin>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</VBox.margin>
</Label>
<LineChart fx:id="heartRateChart">
<xAxis>
<CategoryAxis label="Zeit in s" side="BOTTOM" />
</xAxis>
<yAxis>
<NumberAxis label="BPM" side="LEFT" />
</yAxis>
</LineChart>
<Button fx:id="startBtn" mnemonicParsing="false" onMouseClicked="#startSimulation" text="Button" />
</children>
</VBox>