Adnan
Adnan

Reputation: 69

Why javafx8 UI thread is behaving strangely inside a change listner?

I am creating a bar chart based on user input provided through a choice box. Inside the choice box change listener, I first create a data series and then the bar chart. However, the chart does not render properly, i.e., some time there are no bars, some time the length of bars is not same as the data. But, when I add a short delay between the data creation and chart creation by putting the UI thread to sleep, it works fine.

My question is, why it is happening? Why the UI thread is not waiting for the data creation process to finish before creating the chart? Is there a way to do this without adding a delay? Below is the code snippet of change listener.

numberOfBars.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
   createData(newValue);
   // It works fine if I add Thread.sleep(1000) here. Why?
   createBarChart();
});

The complete code is as follows:

public class Main extends Application {
    private XYChart.Series<String, Number> data = new XYChart.Series<>();
    private VBox vBox = new VBox();
    private Pane bcContainer = new Pane();
    @Override public void start(Stage stage){
        ChoiceBox<Integer> numberOfBars = new ChoiceBox<>();
        ObservableList<Integer> items = FXCollections.observableArrayList(5, 10);
        numberOfBars.setItems(items);
        vBox.getChildren().addAll(new Label("Number of bars: "), numberOfBars, new Separator(), bcContainer);
        numberOfBars.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
            createData(newValue);
            // It works fine if I add Thread.sleep(1000) here. Why?
            createBarChart();
        });
        Scene scene  = new Scene(vBox,800,600);
        stage.setScene(scene);
        stage.show();
    }
    private void createData(int bars){
        ObservableList<XYChart.Data<String, Number>> observableList = FXCollections.observableArrayList();
        for (int i=0; i<bars; i++) {
            observableList.add(new XYChart.Data<>("bar" + Integer.toString(i), i+1));
        }
        data.setData(observableList);
    }
    private void createBarChart(){
        BarChart<String, Number> barChart= new BarChart<>(new CategoryAxis(), new NumberAxis());
        barChart.setLegendVisible(false);
        barChart.setPrefSize(800, 500);
        barChart.getData().add(data);
        bcContainer.getChildren().clear();
        bcContainer.getChildren().add(barChart);
    }
    public static void main(String[] args) {
        launch(args);
    }
}

Upvotes: 0

Views: 38

Answers (1)

James_D
James_D

Reputation: 209339

That looks like a bug... (in the Chart API, I am not entirely surprised).

It seems to work fine if you turn off animation. Call

barChart.setAnimated(false);

immediately after creating the bar chart.

Upvotes: 1

Related Questions