exg
exg

Reputation: 33

How do I plot the line graph properly using a Thread to add data to a XYChart.Serie? (JavaFx)

In the code below, if uncomment this line:

series.getData().add(new XYChart.Data<>(dataValues[columnX], dataValues[columnY]));                 

the data will be plotted but a Thread exception will occurs.

But if uncomment this line instead:

series.getData().add(new XYChart.Series<Number,Number>(data));

no Thread exception occurs but graph will not be plotted.

private XYChart.Series plotLineSeries(String filename, String separator,
        String serieLabel, int columnX, int columnY) {
    XYChart.Series series = new XYChart.Series();
    ObservableList<XYChart.Data<Number, Number>> data = 
                        FXCollections.observableArrayList();

    series.setName(serieLabel);
    Task<Void> task;
    task = new Task<Void>() {
        @Override
        protected Void call() throws Exception {
            BufferedReader br = new BufferedReader(new FileReader(filename));
            String dataLine = br.readLine();                
            while(br.readLine()!=null){
                dataLine = br.readLine();
                final String[] dataValues = dataLine.split(separator);
                data.add(new XYChart.Data(dataValues[columnX],
                    dataValues[columnY]));        

                /* if uncommnent the line below the graph will be plotted, but a thread exception will occur */
                //series.getData().add(new XYChart.Data<>(dataValues[columnX], dataValues[columnY]));                    
            }      
            /*if uncomment the line below no thread exception occurs, but the graph will not be plotted */
            //series.getData().add(new XYChart.Series<Number,Number>(data));

            return null;
        }
    };
    Thread thread = new Thread(task);
    thread.setDaemon(true);
    thread.start();        
    return series;
}   

Upvotes: 0

Views: 539

Answers (1)

James_D
James_D

Reputation: 209319

The first fails because you are updating the chart from a background thread, and as is well-documented you can only change the UI from the FX Application Thread.

The second, I don't really understand what it is supposed to do. You are adding a new series to the list of data points?

Create the list of data and return it from the call method. Then update the chart in a setOnSucceeded(...) handler:

private XYChart.Series plotLineSeries(String filename, String separator,
        String serieLabel, int columnX, int columnY) {
    XYChart.Series<Number, Number> series = new XYChart.Series();

    series.setName(serieLabel);

    Task<List<XYChart.Data<Number, Number>>> task;
    task = new Task<List<XYChart.Data<Number, Number>>>() {
        @Override
        protected List<XYChart.Data<Number, Number>> call() throws Exception {
            BufferedReader br = new BufferedReader(new FileReader(filename));
            List<XYChart.Data<Number,Number>> chartData = new ArrayList<>();
            String dataLine ;                
            while((dataLine = br.readLine())!=null){
                final String[] dataValues = dataLine.split(separator);
                chartData.add(new XYChart.Data(Float.valueOf(dataValues[columnX]),
                    Float.valueOf(dataValues[columnY])));        

            }      

            return chartData;
        }
    };

    task.setOnSucceeded(e -> series.getData().addAll(task.getValue()));

    Thread thread = new Thread(task);
    thread.setDaemon(true);
    thread.start();        
    return series;
}

Upvotes: 1

Related Questions