JavaFX : Data binding et graphique (Line Chart)
Ă€ la fin de cet article, vous devriez avoir le rendu suivant.
Fichier FXML
Vous pouvez nommer le fichier chart-sin.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.chart.LineChart?>
<?import javafx.scene.chart.NumberAxis?>
<?import javafx.scene.control.Slider?>
<?import javafx.scene.layout.VBox?>
<VBox alignment="CENTER" spacing="20.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="fr.ronanlefichant.databinding.ChartSinController">
<padding>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
</padding>
<children>
<LineChart fx:id="lineChart" animated="false" createSymbols="false">
<xAxis>
<NumberAxis side="BOTTOM" />
</xAxis>
<yAxis>
<NumberAxis autoRanging="false" lowerBound="-3.0" side="LEFT" upperBound="3.0" />
</yAxis>
</LineChart>
<Slider fx:id="slider" blockIncrement="0.25" majorTickUnit="0.25" max="2.5" min="-2.5" minorTickCount="0" snapToTicks="true" />
</children>
</VBox>
Vous pouvez enlever l'animation avec la propriété animated="false". Je trouvais l'animation dérangeante dans cet exemple. Elle ajoute un délai et donc le graphique ne se rafraîchissait pas instantanément.
createSymbols="false" supprime l'affichage de tous les points et affiche seulement une ligne.
autoRanging="false" permet de figer l'axe des ordonnées à -3.0 et 3.0.
blockIncrement="0.25" et snapToTicks="true" permettent d'incrémenter ou de décrémenter le curseur de 0.25.
Ce fichier FXML devrait produire une vue comme sur l'image suivante :
Le contrĂ´leur
La vue devrait injecter dans le contrĂ´leur lineChart et slider
@FXML
private LineChart<Double, Double> lineChart;
@FXML
private Slider slider;
Notre contrôleur va implémenter Initializable. Il faut donc créer la fonction initialize
@Override
public void initialize(URL location, ResourceBundle resources) {
/* Ă©coute les changements de valeur du slider et appelle la fonction onSliderValueChanged */
slider.valueProperty().addListener(this::onSliderValueChanged);
/* change la valeur du slider */
slider.setValue(0.25);
}
On ajoute un listener sur la valeur du curseur. Le listener appellera la fonction onSliderValueChanged Ă chaque changement de valeur.
Vous pouvez changer la valeur du curseur maintenant que le listener est installé. On place la valeur à 0.25 par défaut.
Il faut maintenant créer la fonction onSliderValueChanged. Cette fonction va supprimer puis dessiner le graphique à chaque fois que la valeur du curseur change.
private void onSliderValueChanged(ObservableValue<? extends Number> valueObserver, Number oldValue, Number newValue) {
/* suppression des données du graphique */
lineChart.getData().clear();
/* dessine la fonction avec la valeur du slider */
drawFunction(newValue.doubleValue());
}
Il ne reste plus qu'à créer la fonction qui va dessiner le graphique. Dans cet exemple, j'utilise une fonction sinusoïdale. Le curseur va changer l'amplitude de la fonction.
private void drawFunction(double amplitude) {
/* création d'une série */
final XYChart.Series < Double, Double > series = new XYChart.Series < Double, Double > ();
/* création de la légende */
String legend = String.format("y = %.2f . sin(1 . (x - 0)) + 0", amplitude);
series.setName(legend);
/* pour chaque point tous les 0.01 jusqu'Ă 15 */
for (double x = 0; x <= 15; x += 0.01) {
/* ajoute le point (x,y) à la série */
series.getData().add(new XYChart.Data < Double, Double > (x, amplitude * Math.sin(1 * (x - 0)) + 0));
}
/* ajoute la série de point et dessine la fonction */
lineChart.getData().add(series);
}
Tracer tous les 0.01 sur l'axe des abscisses permet d'avoir une ligne bien arrondie.
Le code complet
J'utilise maven avec l'archetype javafx-archetype-fxml de org.openjfx
App.java
package fr.ronanlefichant.databinding;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;
/**
* JavaFX App
*/
public class App extends Application {
private static Scene scene;
@Override
public void start(Stage stage) throws IOException {
scene = new Scene(loadFXML("chart-sin"), 640, 480);
stage.setScene(scene);
stage.show();
}
static void setRoot(String fxml) throws IOException {
scene.setRoot(loadFXML(fxml));
}
private static Parent loadFXML(String fxml) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(App.class.getResource(fxml + ".fxml"));
return fxmlLoader.load();
}
public static void main(String[] args) {
launch();
}
}
ChartSinController.java
package fr.ronanlefichant.databinding;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.beans.value.ObservableValue;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.XYChart;
import javafx.scene.control.Slider;
public class ChartSinController implements Initializable {
@FXML
private LineChart < Double, Double > lineChart;
@FXML
private Slider slider;
@Override
public void initialize(URL location, ResourceBundle resources) {
/* Ă©coute les changements de valeur du slider et appel la fonction onSliderValueChanged */
slider.valueProperty().addListener(this::onSliderValueChanged);
/* change la valeur du slider */
slider.setValue(0.25);
}
private void onSliderValueChanged(ObservableValue << ? extends Number > valueObserver, Number oldValue, Number newValue) {
/* suppression des données du graphique */
lineChart.getData().clear();
/* dessine la fonction avec la valeur du slider */
drawFunction(newValue.doubleValue());
}
private void drawFunction(double amplitude) {
/* création d'une série */
final XYChart.Series < Double, Double > series = new XYChart.Series < Double, Double > ();
/* création de la légende */
String legend = String.format("y = %.2f . sin(1 . (x - 0)) + 0", amplitude);
series.setName(legend);
/* pour chaque point tous les 0.01 jusqu'Ă 15 */
for (double x = 0; x <= 15; x += 0.01) {
/* ajoute le point (x,y) à la série */
series.getData().add(new XYChart.Data < Double, Double > (x, amplitude * Math.sin(1 * (x - 0)) + 0));
}
/* ajoute la série de points et dessine la fonction */
lineChart.getData().add(series);
}
}
module-info.java
module fr.ronanlefichant.databinding {
requires javafx.controls;
requires javafx.fxml;
requires javafx.base;
requires transitive javafx.graphics;
opens fr.ronanlefichant.databinding to javafx.fxml;
exports fr.ronanlefichant.databinding;
}
Commentaires
Enregistrer un commentaire