Add random temperature updates
This commit is contained in:
@@ -8,8 +8,7 @@
|
||||
<?import javafx.scene.control.TextField?>
|
||||
<?import javafx.scene.layout.BorderPane?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<SplitPane xmlns:fx="http://javafx.com/fxml" prefHeight="400.0" prefWidth="600.0"
|
||||
fx:controller="fr.uca.iut.clfreville2.gui.MainWindows">
|
||||
<SplitPane xmlns:fx="http://javafx.com/fxml" prefHeight="400.0" prefWidth="600.0">
|
||||
<ListView fx:id="sensorsList" />
|
||||
<VBox alignment="TOP_CENTER">
|
||||
<padding>
|
||||
|
@@ -1,7 +1,8 @@
|
||||
package fr.uca.iut.clfreville2;
|
||||
|
||||
import fr.uca.iut.clfreville2.gui.FXMLUtils;
|
||||
import fr.uca.iut.clfreville2.gui.MainWindows;
|
||||
import javafx.application.Application;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
@@ -10,7 +11,7 @@ public class MainApplication extends Application {
|
||||
|
||||
@Override
|
||||
public void start(Stage primaryStage) throws Exception {
|
||||
Parent root = FXMLLoader.load(MainApplication.class.getResource("/windows/MainWindows.fxml"));
|
||||
Parent root = FXMLUtils.load(MainApplication.class.getResource("/windows/MainWindows.fxml"), new MainWindows(primaryStage));
|
||||
Scene scene = new Scene(root);
|
||||
primaryStage.setScene(scene);
|
||||
primaryStage.show();
|
||||
|
18
src/fr/uca/iut/clfreville2/gui/FXMLUtils.java
Normal file
18
src/fr/uca/iut/clfreville2/gui/FXMLUtils.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package fr.uca.iut.clfreville2.gui;
|
||||
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Parent;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
|
||||
public final class FXMLUtils {
|
||||
|
||||
private FXMLUtils() {}
|
||||
|
||||
public static Parent load(URL location, Object controller) throws IOException {
|
||||
FXMLLoader loader = new FXMLLoader(location);
|
||||
loader.setController(controller);
|
||||
return loader.load();
|
||||
}
|
||||
}
|
@@ -3,25 +3,27 @@ package fr.uca.iut.clfreville2.gui;
|
||||
import fr.uca.iut.clfreville2.gui.image.ImageSupplier;
|
||||
import fr.uca.iut.clfreville2.gui.image.StandardImageSupplier;
|
||||
import fr.uca.iut.clfreville2.gui.list.NameableListCell;
|
||||
import fr.uca.iut.clfreville2.gui.thread.Ticker;
|
||||
import fr.uca.iut.clfreville2.model.SensorRegistry;
|
||||
import fr.uca.iut.clfreville2.model.binding.ToBooleanBinding;
|
||||
import fr.uca.iut.clfreville2.model.sensor.ManualSensor;
|
||||
import fr.uca.iut.clfreville2.model.sensor.Sensor;
|
||||
import fr.uca.iut.clfreville2.persistence.StubSensorRegistryLoader;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ListView;
|
||||
import javafx.scene.control.Slider;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.text.Text;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
public class MainWindows {
|
||||
|
||||
private final SensorRegistry registry = new StubSensorRegistryLoader().load();
|
||||
private final ImageSupplier imageSupplier = new StandardImageSupplier();
|
||||
private ModalFactory modalFactory;
|
||||
private final Ticker ticker;
|
||||
private final ModalFactory modalFactory;
|
||||
|
||||
@FXML
|
||||
private ListView<Sensor> sensorsList;
|
||||
@@ -38,13 +40,20 @@ public class MainWindows {
|
||||
@FXML
|
||||
private Button visualizeBtn;
|
||||
|
||||
public MainWindows(Stage primaryStage) {
|
||||
this.ticker = new Ticker(registry);
|
||||
this.modalFactory = new ModalFactory(primaryStage);
|
||||
primaryStage.setOnHidden((e) -> ticker.interrupt());
|
||||
ticker.start();
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void onChangeClick() {
|
||||
Sensor selected = getSelectedSensor();
|
||||
if (!(selected instanceof ManualSensor sensor)) {
|
||||
return;
|
||||
}
|
||||
getModalFactory().createModal(selected, root -> {
|
||||
modalFactory.createModal(selected, root -> {
|
||||
Slider slider = new Slider(-5, 30, sensor.getTemperature());
|
||||
slider.setBlockIncrement(0.5);
|
||||
slider.setMajorTickUnit(0.5);
|
||||
@@ -61,7 +70,7 @@ public class MainWindows {
|
||||
if (selected == null) {
|
||||
return;
|
||||
}
|
||||
getModalFactory().createModal(selected, root -> {
|
||||
modalFactory.createModal(selected, root -> {
|
||||
ImageView imageView = new ImageView();
|
||||
imageView.setPreserveRatio(true);
|
||||
imageView.setFitHeight(200);
|
||||
@@ -107,15 +116,4 @@ public class MainWindows {
|
||||
private Sensor getSelectedSensor() {
|
||||
return sensorsList.getSelectionModel().getSelectedItem();
|
||||
}
|
||||
|
||||
private ModalFactory getModalFactory() {
|
||||
if (modalFactory == null) {
|
||||
Scene scene = sensorsList.getScene();
|
||||
if (scene == null) {
|
||||
throw new IllegalStateException("No scene found");
|
||||
}
|
||||
modalFactory = new ModalFactory(scene.getWindow());
|
||||
}
|
||||
return modalFactory;
|
||||
}
|
||||
}
|
||||
|
40
src/fr/uca/iut/clfreville2/gui/thread/Ticker.java
Normal file
40
src/fr/uca/iut/clfreville2/gui/thread/Ticker.java
Normal file
@@ -0,0 +1,40 @@
|
||||
package fr.uca.iut.clfreville2.gui.thread;
|
||||
|
||||
import fr.uca.iut.clfreville2.model.shared.Tickable;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.IntegerProperty;
|
||||
import javafx.beans.property.SimpleIntegerProperty;
|
||||
|
||||
public class Ticker extends Thread {
|
||||
|
||||
private final Tickable tickable;
|
||||
private final IntegerProperty millisPerTick = new SimpleIntegerProperty(250);
|
||||
|
||||
public Ticker(Tickable tickable) {
|
||||
this.tickable = tickable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (true) {
|
||||
try {
|
||||
Thread.sleep(millisPerTick.getValue());
|
||||
Platform.runLater(tickable::tick);
|
||||
} catch (InterruptedException e) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getMillisPerTick() {
|
||||
return millisPerTick.get();
|
||||
}
|
||||
|
||||
public void setMillisPerTick(int millisPerTick) {
|
||||
this.millisPerTick.set(millisPerTick);
|
||||
}
|
||||
|
||||
public IntegerProperty millisPerTickProperty() {
|
||||
return millisPerTick;
|
||||
}
|
||||
}
|
@@ -1,7 +1,10 @@
|
||||
package fr.uca.iut.clfreville2.model;
|
||||
|
||||
import fr.uca.iut.clfreville2.model.sensor.AutoSensor;
|
||||
import fr.uca.iut.clfreville2.model.sensor.ManualSensor;
|
||||
import fr.uca.iut.clfreville2.model.sensor.Sensor;
|
||||
import fr.uca.iut.clfreville2.model.sensor.auto.AutoUpdateStrategy;
|
||||
import fr.uca.iut.clfreville2.model.shared.Tickable;
|
||||
import javafx.beans.property.ListProperty;
|
||||
import javafx.beans.property.ReadOnlyListProperty;
|
||||
import javafx.beans.property.SimpleListProperty;
|
||||
@@ -14,7 +17,7 @@ import java.util.function.IntSupplier;
|
||||
/**
|
||||
* A registry class to hold thermal sensors instances.
|
||||
*/
|
||||
public class SensorRegistry implements Iterable<Sensor> {
|
||||
public class SensorRegistry implements Tickable, Iterable<Sensor> {
|
||||
|
||||
private final IntSupplier nextIdSupplier = new SequenceIntSupplier();
|
||||
private final ObservableList<Sensor> sensors = FXCollections.observableArrayList();
|
||||
@@ -30,6 +33,17 @@ public class SensorRegistry implements Iterable<Sensor> {
|
||||
return register(new ManualSensor(nextIdSupplier.getAsInt(), name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new auto sensor and add it to the registry.
|
||||
*
|
||||
* @param name The name of the sensor.
|
||||
* @param strategy The strategy to update the sensor.
|
||||
* @return The sensor created.
|
||||
*/
|
||||
public AutoSensor createAuto(String name, AutoUpdateStrategy strategy) {
|
||||
return register(new AutoSensor(nextIdSupplier.getAsInt(), name, strategy));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new sensor to the registry.
|
||||
*
|
||||
@@ -60,6 +74,15 @@ public class SensorRegistry implements Iterable<Sensor> {
|
||||
return sensorsList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
for (Sensor sensor : sensors) {
|
||||
if (sensor instanceof Tickable tickable) {
|
||||
tickable.tick();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Sensor> iterator() {
|
||||
return getSensors().iterator();
|
||||
|
41
src/fr/uca/iut/clfreville2/model/sensor/AutoSensor.java
Normal file
41
src/fr/uca/iut/clfreville2/model/sensor/AutoSensor.java
Normal file
@@ -0,0 +1,41 @@
|
||||
package fr.uca.iut.clfreville2.model.sensor;
|
||||
|
||||
import fr.uca.iut.clfreville2.model.sensor.auto.AutoUpdateStrategy;
|
||||
import fr.uca.iut.clfreville2.model.shared.Tickable;
|
||||
import javafx.beans.property.DoubleProperty;
|
||||
import javafx.beans.property.ReadOnlyDoubleProperty;
|
||||
import javafx.beans.property.SimpleDoubleProperty;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
/**
|
||||
* A sensor that automatically create new temperatures.
|
||||
*/
|
||||
public class AutoSensor extends Sensor implements Tickable {
|
||||
|
||||
private final DoubleProperty temperature = new SimpleDoubleProperty();
|
||||
private AutoUpdateStrategy updateStrategy;
|
||||
|
||||
public AutoSensor(int id, String name, AutoUpdateStrategy updateStrategy) {
|
||||
super(id, name);
|
||||
this.updateStrategy = requireNonNull(updateStrategy, "update strategy");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
temperature.set(updateStrategy.nextValue(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReadOnlyDoubleProperty temperatureProperty() {
|
||||
return temperature;
|
||||
}
|
||||
|
||||
public AutoUpdateStrategy getUpdateStrategy() {
|
||||
return updateStrategy;
|
||||
}
|
||||
|
||||
public void setUpdateStrategy(AutoUpdateStrategy updateStrategy) {
|
||||
this.updateStrategy = requireNonNull(updateStrategy, "update strategy");
|
||||
}
|
||||
}
|
@@ -2,16 +2,13 @@ package fr.uca.iut.clfreville2.model.sensor;
|
||||
|
||||
import fr.uca.iut.clfreville2.model.shared.TemperatureHolder;
|
||||
import fr.uca.iut.clfreville2.model.shared.ObservableIdentifiable;
|
||||
import javafx.beans.binding.DoubleBinding;
|
||||
import javafx.beans.binding.DoubleExpression;
|
||||
import javafx.beans.binding.StringExpression;
|
||||
import javafx.beans.property.IntegerProperty;
|
||||
import javafx.beans.property.ReadOnlyDoubleProperty;
|
||||
import javafx.beans.property.ReadOnlyIntegerProperty;
|
||||
import javafx.beans.property.SimpleIntegerProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import javafx.beans.value.ObservableDoubleValue;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
|
@@ -0,0 +1,15 @@
|
||||
package fr.uca.iut.clfreville2.model.sensor.auto;
|
||||
|
||||
import fr.uca.iut.clfreville2.model.sensor.AutoSensor;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface AutoUpdateStrategy {
|
||||
|
||||
/**
|
||||
* Computes the next value of the sensor.
|
||||
*
|
||||
* @param currentState The current state of the sensor.
|
||||
* @return The next value of the sensor.
|
||||
*/
|
||||
double nextValue(AutoSensor currentState);
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
package fr.uca.iut.clfreville2.model.sensor.auto;
|
||||
|
||||
import fr.uca.iut.clfreville2.model.sensor.AutoSensor;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class RandomVariationStrategy implements AutoUpdateStrategy {
|
||||
|
||||
private final Random random;
|
||||
private final int maxVariation;
|
||||
|
||||
public RandomVariationStrategy(int maxVariation) {
|
||||
this(new Random(), maxVariation);
|
||||
}
|
||||
|
||||
public RandomVariationStrategy(Random random, int maxVariation) {
|
||||
this.random = random;
|
||||
this.maxVariation = maxVariation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double nextValue(AutoSensor currentState) {
|
||||
return currentState.getTemperature() + random.nextInt(maxVariation * 2) - maxVariation;
|
||||
}
|
||||
}
|
@@ -31,5 +31,12 @@ public interface ObservableIdentifiable extends Identifiable {
|
||||
* @return The display name.
|
||||
* @see #getDisplayName()
|
||||
*/
|
||||
StringExpression displayNameExpression();
|
||||
default StringExpression displayNameExpression() {
|
||||
return nameProperty();
|
||||
}
|
||||
|
||||
@Override
|
||||
default String getDisplayName() {
|
||||
return displayNameExpression().get();
|
||||
}
|
||||
}
|
||||
|
10
src/fr/uca/iut/clfreville2/model/shared/Tickable.java
Normal file
10
src/fr/uca/iut/clfreville2/model/shared/Tickable.java
Normal file
@@ -0,0 +1,10 @@
|
||||
package fr.uca.iut.clfreville2.model.shared;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Tickable {
|
||||
|
||||
/**
|
||||
* Tick the current object.
|
||||
*/
|
||||
void tick();
|
||||
}
|
@@ -1,6 +1,7 @@
|
||||
package fr.uca.iut.clfreville2.persistence;
|
||||
|
||||
import fr.uca.iut.clfreville2.model.SensorRegistry;
|
||||
import fr.uca.iut.clfreville2.model.sensor.auto.RandomVariationStrategy;
|
||||
|
||||
public class StubSensorRegistryLoader implements SensorRegistryLoader {
|
||||
@Override
|
||||
@@ -8,7 +9,7 @@ public class StubSensorRegistryLoader implements SensorRegistryLoader {
|
||||
SensorRegistry registry = new SensorRegistry();
|
||||
registry.createManual("Sensor 1");
|
||||
registry.createManual("Sensor 2");
|
||||
registry.createManual("Sensor 3");
|
||||
registry.createAuto("Sensor 3", new RandomVariationStrategy(5));
|
||||
return registry;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user