A DESCRIPTION OF THE PROBLEM :
When I replace all Series with new series, the new series' data-elements get wrong style-classes for default-color. For the first 8 series, the numbering is correct, for all other, the numbering is shifted.
See here for a detailed description:
https://stackoverflow.com/questions/51893749/javafx-xycharts-weird-behaviour-on-replacing-all-series
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
import javafx.application.Application;
import javafx.beans.InvalidationListener;
import javafx.scene.Scene;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.ScatterChart;
import javafx.scene.chart.XYChart;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.util.ArrayList;
import java.util.List;
public class ChartSeriesReplacing extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
VBox root = new VBox();
ScatterChart<Number, Number> chart = new ScatterChart<>(new NumberAxis(), new NumberAxis());
Button refresh = new Button("Refresh");
refresh.setOnAction(clicked -> {
List<XYChart.Series<Number, Number>> seriesList = new ArrayList<>();
for (int i = 0; i < 15; i++) {
XYChart.Series<Number, Number> series = new XYChart.Series<>();
series.setName(i + "");
XYChart.Data<Number, Number> data = new XYChart.Data<>(Math.random(), Math.random());
int finalI = i;
data.nodeProperty().addListener(__ -> {
if (data.getNode() != null) {
data.getNode().getStyleClass().addListener((InvalidationListener) ___ -> {
// System.out.println("[pre] Data #" + finalI + ": Style = " + data.getNode().getStyleClass());
// DIRTY-WORKAROUND-SOLUTION:
// (has to live in listener, otherwise the chart erases any custom styling on adding... :-/ )
// String colorString = "default-color" + finalI % 8;
// data.getNode().getStyleClass().removeIf(s -> s.startsWith("default-color") && !s.equals(colorString));
// if (!data.getNode().getStyleClass().contains(colorString)) {
// data.getNode().getStyleClass().add(colorString);
// }
// --------------------------
System.out.println("[post] Data #" + finalI + ": Style = " + data.getNode().getStyleClass());
});
}
});
series.getData().add(data);
seriesList.add(series);
}
System.out.println("-----------------");
// What I tried:
// 1)
chart.getData().setAll(seriesList);
// 2)
// chart.dataProperty().setValue(FXCollections.observableArrayList(seriesList));
// 3)
// chart.getData().clear();
// 3a)
// chart.getData().addAll(seriesList);
// 3b)
// seriesList.forEach(series->chart.getData().add(series));
});
root.getChildren().add(chart);
root.getChildren().add(refresh);
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
}
// --> hit "refresh" multiple times
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
[post] Data #0: Style = chart-symbol series0 data0 default-color0
[post] Data #1: Style = chart-symbol series1 data0 default-color1
[post] Data #2: Style = chart-symbol series2 data0 default-color2
[post] Data #3: Style = chart-symbol series3 data0 default-color3
[post] Data #4: Style = chart-symbol series4 data0 default-color4
[post] Data #5: Style = chart-symbol series5 data0 default-color5
[post] Data #6: Style = chart-symbol series6 data0 default-color6
[post] Data #7: Style = chart-symbol series7 data0 default-color7
[post] Data #8: Style = chart-symbol series8 data0 default-color0
[post] Data #9: Style = chart-symbol series9 data0 default-color1
[post] Data #10: Style = chart-symbol series10 data0 default-color2
[post] Data #11: Style = chart-symbol series11 data0 default-color3
[post] Data #12: Style = chart-symbol series12 data0 default-color4
[post] Data #13: Style = chart-symbol series13 data0 default-color5
[post] Data #14: Style = chart-symbol series14 data0 default-color6
for every click on "refresh"
ACTUAL -
for 1st click as expected.
for 2nd click:
[post] Data #1: Style = chart-symbol series1 data0 default-color0
[post] Data #2: Style = chart-symbol series2 data0 default-color1
[post] Data #3: Style = chart-symbol series3 data0 default-color2
[post] Data #4: Style = chart-symbol series4 data0 default-color3
[post] Data #5: Style = chart-symbol series5 data0 default-color4
[post] Data #6: Style = chart-symbol series6 data0 default-color5
[post] Data #7: Style = chart-symbol series7 data0 default-color6
[post] Data #8: Style = chart-symbol series8 data0 default-color7
[post] Data #9: Style = chart-symbol series9 data0 default-color7 <-- from here on shifted!
[post] Data #10: Style = chart-symbol series10 data0 default-color0
[post] Data #11: Style = chart-symbol series11 data0 default-color1
[post] Data #12: Style = chart-symbol series12 data0 default-color2
[post] Data #13: Style = chart-symbol series13 data0 default-color3
[post] Data #14: Style = chart-symbol series14 data0 default-color4
[post] Data #0: Style = chart-symbol series0 data0 default-color0
for 3rd click:
[post] Data #1: Style = chart-symbol series1 data0 default-color0
[post] Data #2: Style = chart-symbol series2 data0 default-color1
[post] Data #3: Style = chart-symbol series3 data0 default-color2
[post] Data #4: Style = chart-symbol series4 data0 default-color3
[post] Data #5: Style = chart-symbol series5 data0 default-color4
[post] Data #6: Style = chart-symbol series6 data0 default-color5
[post] Data #7: Style = chart-symbol series7 data0 default-color6
[post] Data #8: Style = chart-symbol series8 data0 default-color7
[post] Data #9: Style = chart-symbol series9 data0 default-color5 <-- !!
[post] Data #10: Style = chart-symbol series10 data0 default-color6
[post] Data #11: Style = chart-symbol series11 data0 default-color7
[post] Data #12: Style = chart-symbol series12 data0 default-color0
[post] Data #13: Style = chart-symbol series13 data0 default-color1
[post] Data #14: Style = chart-symbol series14 data0 default-color2
[post] Data #0: Style = chart-symbol series0 data0 default-color0
---------- BEGIN SOURCE ----------
import javafx.application.Application;
import javafx.beans.InvalidationListener;
import javafx.scene.Scene;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.ScatterChart;
import javafx.scene.chart.XYChart;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.util.ArrayList;
import java.util.List;
public class ChartSeriesReplacing extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
VBox root = new VBox();
ScatterChart<Number, Number> chart = new ScatterChart<>(new NumberAxis(), new NumberAxis());
Button refresh = new Button("Refresh");
refresh.setOnAction(clicked -> {
List<XYChart.Series<Number, Number>> seriesList = new ArrayList<>();
for (int i = 0; i < 15; i++) {
XYChart.Series<Number, Number> series = new XYChart.Series<>();
series.setName(i + "");
XYChart.Data<Number, Number> data = new XYChart.Data<>(Math.random(), Math.random());
int finalI = i;
data.nodeProperty().addListener(__ -> {
if (data.getNode() != null) {
data.getNode().getStyleClass().addListener((InvalidationListener) ___ -> {
// System.out.println("[pre] Data #" + finalI + ": Style = " + data.getNode().getStyleClass());
// DIRTY-WORKAROUND-SOLUTION:
// (has to live in listener, otherwise the chart erases any custom styling on adding... :-/ )
// String colorString = "default-color" + finalI % 8;
// data.getNode().getStyleClass().removeIf(s -> s.startsWith("default-color") && !s.equals(colorString));
// if (!data.getNode().getStyleClass().contains(colorString)) {
// data.getNode().getStyleClass().add(colorString);
// }
// --------------------------
System.out.println("[post] Data #" + finalI + ": Style = " + data.getNode().getStyleClass());
});
}
});
series.getData().add(data);
seriesList.add(series);
}
System.out.println("-----------------");
// What I tried:
// 1)
chart.getData().setAll(seriesList);
// 2)
// chart.dataProperty().setValue(FXCollections.observableArrayList(seriesList));
// 3)
// chart.getData().clear();
// 3a)
// chart.getData().addAll(seriesList);
// 3b)
// seriesList.forEach(series->chart.getData().add(series));
});
root.getChildren().add(chart);
root.getChildren().add(refresh);
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
uncomment the lines titeled dirty workaround.
FREQUENCY : always
When I replace all Series with new series, the new series' data-elements get wrong style-classes for default-color. For the first 8 series, the numbering is correct, for all other, the numbering is shifted.
See here for a detailed description:
https://stackoverflow.com/questions/51893749/javafx-xycharts-weird-behaviour-on-replacing-all-series
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
import javafx.application.Application;
import javafx.beans.InvalidationListener;
import javafx.scene.Scene;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.ScatterChart;
import javafx.scene.chart.XYChart;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.util.ArrayList;
import java.util.List;
public class ChartSeriesReplacing extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
VBox root = new VBox();
ScatterChart<Number, Number> chart = new ScatterChart<>(new NumberAxis(), new NumberAxis());
Button refresh = new Button("Refresh");
refresh.setOnAction(clicked -> {
List<XYChart.Series<Number, Number>> seriesList = new ArrayList<>();
for (int i = 0; i < 15; i++) {
XYChart.Series<Number, Number> series = new XYChart.Series<>();
series.setName(i + "");
XYChart.Data<Number, Number> data = new XYChart.Data<>(Math.random(), Math.random());
int finalI = i;
data.nodeProperty().addListener(__ -> {
if (data.getNode() != null) {
data.getNode().getStyleClass().addListener((InvalidationListener) ___ -> {
// System.out.println("[pre] Data #" + finalI + ": Style = " + data.getNode().getStyleClass());
// DIRTY-WORKAROUND-SOLUTION:
// (has to live in listener, otherwise the chart erases any custom styling on adding... :-/ )
// String colorString = "default-color" + finalI % 8;
// data.getNode().getStyleClass().removeIf(s -> s.startsWith("default-color") && !s.equals(colorString));
// if (!data.getNode().getStyleClass().contains(colorString)) {
// data.getNode().getStyleClass().add(colorString);
// }
// --------------------------
System.out.println("[post] Data #" + finalI + ": Style = " + data.getNode().getStyleClass());
});
}
});
series.getData().add(data);
seriesList.add(series);
}
System.out.println("-----------------");
// What I tried:
// 1)
chart.getData().setAll(seriesList);
// 2)
// chart.dataProperty().setValue(FXCollections.observableArrayList(seriesList));
// 3)
// chart.getData().clear();
// 3a)
// chart.getData().addAll(seriesList);
// 3b)
// seriesList.forEach(series->chart.getData().add(series));
});
root.getChildren().add(chart);
root.getChildren().add(refresh);
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
}
// --> hit "refresh" multiple times
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
[post] Data #0: Style = chart-symbol series0 data0 default-color0
[post] Data #1: Style = chart-symbol series1 data0 default-color1
[post] Data #2: Style = chart-symbol series2 data0 default-color2
[post] Data #3: Style = chart-symbol series3 data0 default-color3
[post] Data #4: Style = chart-symbol series4 data0 default-color4
[post] Data #5: Style = chart-symbol series5 data0 default-color5
[post] Data #6: Style = chart-symbol series6 data0 default-color6
[post] Data #7: Style = chart-symbol series7 data0 default-color7
[post] Data #8: Style = chart-symbol series8 data0 default-color0
[post] Data #9: Style = chart-symbol series9 data0 default-color1
[post] Data #10: Style = chart-symbol series10 data0 default-color2
[post] Data #11: Style = chart-symbol series11 data0 default-color3
[post] Data #12: Style = chart-symbol series12 data0 default-color4
[post] Data #13: Style = chart-symbol series13 data0 default-color5
[post] Data #14: Style = chart-symbol series14 data0 default-color6
for every click on "refresh"
ACTUAL -
for 1st click as expected.
for 2nd click:
[post] Data #1: Style = chart-symbol series1 data0 default-color0
[post] Data #2: Style = chart-symbol series2 data0 default-color1
[post] Data #3: Style = chart-symbol series3 data0 default-color2
[post] Data #4: Style = chart-symbol series4 data0 default-color3
[post] Data #5: Style = chart-symbol series5 data0 default-color4
[post] Data #6: Style = chart-symbol series6 data0 default-color5
[post] Data #7: Style = chart-symbol series7 data0 default-color6
[post] Data #8: Style = chart-symbol series8 data0 default-color7
[post] Data #9: Style = chart-symbol series9 data0 default-color7 <-- from here on shifted!
[post] Data #10: Style = chart-symbol series10 data0 default-color0
[post] Data #11: Style = chart-symbol series11 data0 default-color1
[post] Data #12: Style = chart-symbol series12 data0 default-color2
[post] Data #13: Style = chart-symbol series13 data0 default-color3
[post] Data #14: Style = chart-symbol series14 data0 default-color4
[post] Data #0: Style = chart-symbol series0 data0 default-color0
for 3rd click:
[post] Data #1: Style = chart-symbol series1 data0 default-color0
[post] Data #2: Style = chart-symbol series2 data0 default-color1
[post] Data #3: Style = chart-symbol series3 data0 default-color2
[post] Data #4: Style = chart-symbol series4 data0 default-color3
[post] Data #5: Style = chart-symbol series5 data0 default-color4
[post] Data #6: Style = chart-symbol series6 data0 default-color5
[post] Data #7: Style = chart-symbol series7 data0 default-color6
[post] Data #8: Style = chart-symbol series8 data0 default-color7
[post] Data #9: Style = chart-symbol series9 data0 default-color5 <-- !!
[post] Data #10: Style = chart-symbol series10 data0 default-color6
[post] Data #11: Style = chart-symbol series11 data0 default-color7
[post] Data #12: Style = chart-symbol series12 data0 default-color0
[post] Data #13: Style = chart-symbol series13 data0 default-color1
[post] Data #14: Style = chart-symbol series14 data0 default-color2
[post] Data #0: Style = chart-symbol series0 data0 default-color0
---------- BEGIN SOURCE ----------
import javafx.application.Application;
import javafx.beans.InvalidationListener;
import javafx.scene.Scene;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.ScatterChart;
import javafx.scene.chart.XYChart;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.util.ArrayList;
import java.util.List;
public class ChartSeriesReplacing extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
VBox root = new VBox();
ScatterChart<Number, Number> chart = new ScatterChart<>(new NumberAxis(), new NumberAxis());
Button refresh = new Button("Refresh");
refresh.setOnAction(clicked -> {
List<XYChart.Series<Number, Number>> seriesList = new ArrayList<>();
for (int i = 0; i < 15; i++) {
XYChart.Series<Number, Number> series = new XYChart.Series<>();
series.setName(i + "");
XYChart.Data<Number, Number> data = new XYChart.Data<>(Math.random(), Math.random());
int finalI = i;
data.nodeProperty().addListener(__ -> {
if (data.getNode() != null) {
data.getNode().getStyleClass().addListener((InvalidationListener) ___ -> {
// System.out.println("[pre] Data #" + finalI + ": Style = " + data.getNode().getStyleClass());
// DIRTY-WORKAROUND-SOLUTION:
// (has to live in listener, otherwise the chart erases any custom styling on adding... :-/ )
// String colorString = "default-color" + finalI % 8;
// data.getNode().getStyleClass().removeIf(s -> s.startsWith("default-color") && !s.equals(colorString));
// if (!data.getNode().getStyleClass().contains(colorString)) {
// data.getNode().getStyleClass().add(colorString);
// }
// --------------------------
System.out.println("[post] Data #" + finalI + ": Style = " + data.getNode().getStyleClass());
});
}
});
series.getData().add(data);
seriesList.add(series);
}
System.out.println("-----------------");
// What I tried:
// 1)
chart.getData().setAll(seriesList);
// 2)
// chart.dataProperty().setValue(FXCollections.observableArrayList(seriesList));
// 3)
// chart.getData().clear();
// 3a)
// chart.getData().addAll(seriesList);
// 3b)
// seriesList.forEach(series->chart.getData().add(series));
});
root.getChildren().add(chart);
root.getChildren().add(refresh);
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
uncomment the lines titeled dirty workaround.
FREQUENCY : always