Issue
I made this code that creates a scatter chart and allows me to change the color of a node on the plot when I click/select it.
package com.jpc.javafx.charttest;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.ScatterChart;
import javafx.scene.chart.XYChart;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class CreateChart extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
//-------Create Chart--------------
NumberAxis xAxis = new NumberAxis();
NumberAxis yAxis = new NumberAxis();
XYChart.Series<Number,Number> dataSeries1 = new XYChart.Series();
ScatterChart chart = new ScatterChart(xAxis,yAxis);
dataSeries1.getData().add(new XYChart.Data( 1, 567));
dataSeries1.getData().add(new XYChart.Data( 5, 612));
dataSeries1.getData().add(new XYChart.Data(10, 800));
chart.getData().add(dataSeries1);
//-----Select node and change color -----
for(final XYChart.Data<Number,Number> data : dataSeries1.getData()) {
data.getNode().setOnMouseClicked(e-> {
//dataSeries1.getNode().lookup(".chart-symbol").setStyle("-fx-background-color: red"); that does not work
data.getNode().setStyle("-fx-background-color: blue" );
});
}
VBox vbox = new VBox(chart);
Scene scene = new Scene(vbox, 400, 200);
primaryStage.setScene(scene);
primaryStage.setHeight(300);
primaryStage.setWidth(1200);
primaryStage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}
The problem is that when I select another point the previous one stays blue. So I need to reset all the nodes to the default color before I change the selected point's color. I tried to add this:
dataSeries1.getNode().lookup(".chart-symbol").setStyle("-fx-background-color: red");
but I get:
Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
Solution
To summarize your requirement:
- a visual property of a chart-symbol should be marked on user interaction
- there should be only one such marked symbol
Sounds like a kind of selection mechanism - which is not supported for chart symbols out of the box, application code must take care of it. The task is
- keep track of the (last) selected symbol
- guarantee that at any time only a single symbol is selected
- keep the visual state of un/selected as needed
The most simple implementation for the logic (the first two bullets) would be to keep a reference to the current selected and update it on user interaction. An appropriate instrument for the latter would be a PseudoClass: can be defined in the css and de/activated along with the logic.
Code snippets (to be inserted into your example)
// Pseudo-class
private PseudoClass selected = PseudoClass.getPseudoClass("selected");
// selected logic
private Node selectedSymbol;
protected void setSelectedSymbol(Node symbol) {
if (selectedSymbol != null) {
selectedSymbol.pseudoClassStateChanged(selected, false);
}
selectedSymbol = symbol;
if (selectedSymbol != null) {
selectedSymbol.pseudoClassStateChanged(selected, true);
}
}
// event handler on every symbol
data.getNode().setOnXX(e -> setSelectedSymbol(data.getNode()));
css example, to be loaded via a style-sheet f.i.:
.chart-symbol:selected {
-fx-background-color: blue;
}
Answered By - kleopatra