I have some problem with updating my Chart
I have class Chart
public class Chart {
public LineChart<String, Number> createChart() {
// defining the axes
final CategoryAxis xAxis = new CategoryAxis(); // we are gonna plot against time
final NumberAxis yAxis = new NumberAxis();
xAxis.setLabel("Time/s");
xAxis.setAnimated(false); // axis animations are removed
yAxis.setLabel("Value");
yAxis.setAnimated(false); // axis animations are removed
// creating the line chart with two axis created above
final LineChart<String, Number> lineChart = new LineChart<>(xAxis, yAxis);
lineChart.setAnimated(false); // disable animations
// defining a series to display data
XYChart.Series<String, Number> series = new XYChart.Series<>();
series.setName("Data Series");
// add series to chart
lineChart.getData().add(series);
return lineChart;
}
}
And main class
public class Main extends Application {
final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm:ss");
private Service service;
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("Hello World");
primaryStage.setWidth(500);
primaryStage.setHeight(500);
Chart chart = new Chart();
LineChart<String, Number> lineChart = chart.createChart();
// setup scene
Scene scene = new Scene(lineChart, 800, 600);
primaryStage.setScene(scene);
createService();
primaryStage.show();
startService();
// First variant
Platform.runLater(() -> lineChart.getData().get(0).getData().add((XYChart.Data<String, Number>) service.valueProperty().getValue()));
//Second variant
lineChart.getData().get(0).getData().add((XYChart.Data<String, Number>) service.valueProperty().getValue());
//Third variant
lineChart.getData().get(0).dataProperty().bind(service.valueProperty());
}
private void createService() {
service = new Service<ObservableList<XYChart.Data<String, Number>>>() {
@Override
protected Task<ObservableList<XYChart.Data<String, Number>>> createTask() {
return new Task<ObservableList<XYChart.Data<String, Number>>>() {
Date now;
Integer random;
@Override
protected ObservableList<XYChart.Data<String, Number>> call() throws InterruptedException {
for (int i = 0; i < 10; i++) {
now = new Date();
random = ThreadLocalRandom.current().nextInt(10);
System.out.println(simpleDateFormat.format(now) + " " + random);
updateValue(FXCollections.observableArrayList(new XYChart.Data(simpleDateFormat.format(now), random)));
Thread.sleep(500);
}
return FXCollections.observableArrayList(new XYChart.Data(simpleDateFormat.format(now), random));
}
};
}
};
}
private void startService() {
if (!service.isRunning()) {
service.reset();
service.start();
}
}
}
The first and second variants from Main class throw exception Exception in thread "JavaFX Application Thread" java.lang.NullPointerException and doesn't update my Chart, but the third one updates it but it update, but I need to add new value to my graphic
How can I update my code to add all 10 values into graph instead only 1 or only last one?
I had to change my Main class to
public class Main extends Application {
final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm:ss");
private LineChart<String, Number> lineChart;
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("Hello World");
primaryStage.setWidth(500);
primaryStage.setHeight(500);
Chart chart = new Chart();
lineChart = chart.createChart();
// setup scene
Scene scene = new Scene(lineChart, 800, 600);
primaryStage.setScene(scene);
createService();
primaryStage.show();
}
private void createService() {
Task<Void> task = new Task<Void>() {
Date now;
Integer random;
@Override
protected Void call() throws InterruptedException {
for (int i = 0; i < 10; i++) {
now = new Date();
random = ThreadLocalRandom.current().nextInt(10);
System.out.println(simpleDateFormat.format(now) + " " + random);
Platform.runLater(() -> updateChart(now, random));
Thread.sleep(500);
}
return null;
}
};
Thread thread = new Thread(task);
thread.setDaemon(true);
thread.start();
}
private void updateChart(Date now, Integer random) {
lineChart.getData().get(0).getData().add(new XYChart.Data(simpleDateFormat.format(now), random));
}
}
valueProperty.getValue()
might be null since service task execution might not reach setValue
call yet. But most important thing is that this cast
Platform.runLater(() -> lineChart.getData().get(0).getData().add(/*here -->*/(XYChart.Data<String, Number>) service.valueProperty().getValue()));
does not make sense. Service valueProperty
type is ObservableList<XYChart.Data<String, Number>>
as specified in line
service = new Service<ObservableList<XYChart.Data<String, Number>>>()
If you wanted to add current service value you'd rather should use ObservableList::addAll
method and cast value to list type:
Platform.runLater(() -> lineChart.getData().get(0).getData().addAll((ObservableList<XYChart.Data<String, Number>>)service.valueProperty().getValue()));
Also since you know what type of service you'd have later you can already specify its full type in declaration by changing:
private Service service;
into
private Service<ObservableList<XYChart.Data<String, Number>>> service;
resulting in just:
Platform.runLater(() -> lineChart.getData().get(0).getData().addAll(service.getValue()));
Basically same story as for first variant but additionaly you make changes not on the UI thread so this might cause troubles when updating chart.
You overwrite service value
with list containing only one element:
// each time new list!
updateValue(FXCollections.observableArrayList(new XYChart.Data(simpleDateFormat.format(now), random)));
In the service definition you should create one list and append points to that list
private void createService() {
service = new Service<ObservableList<XYChart.Data<String, Number>>>() {
@Override
protected Task<ObservableList<XYChart.Data<String, Number>>> createTask() {
return new Task<ObservableList<XYChart.Data<String, Number>>>() {
Date now;
Integer random;
// Specify ONE list
ObservableList<XYChart.Data<String, Number>> data = FXCollections.observableArrayList();
@Override
protected ObservableList<XYChart.Data<String, Number>> call() throws InterruptedException {
updateValue(data);
for (int i = 0; i < 10; i++) {
now = new Date();
random = ThreadLocalRandom.current().nextInt(10);
System.out.println(simpleDateFormat.format(now) + " " + random);
// Add points to the data (on UI thread to have chart updated properly!)
Platform.runLater(() -> data.add(new XYChart.Data(simpleDateFormat.format(now), random)));
Thread.sleep(500);
}
return data;
}
};
}
};
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.