如何从另外两个系列中获得一个系列?

时间:2019-05-21 10:08:41

标签: java javafx charts binding series

我正在JavaFX中构建XYChart。它包含两个系列(系列1&2)和第三个系列(系列3),其值应为系列1和2的总和。

现在,如果对系列1或2的值进行了更改(添加,删除,更改等),则系列3应该自动更新。

实现此目标的最佳方法是什么?

谢谢。

package lineChart;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.stage.Stage;

public class LineChartSample extends Application {

    @Override
    public void start(Stage stage) {
        final NumberAxis xAxis = new NumberAxis();
        final NumberAxis yAxis = new NumberAxis();
        final LineChart<Number, Number> lineChart = new LineChart<Number, Number>(xAxis, yAxis);

        XYChart.Series series1 = new XYChart.Series();


        series1.getData().add(new XYChart.Data(1, 10));
        series1.getData().add(new XYChart.Data(10, 20));
        series1.getData().add(new XYChart.Data(20, 30));
        lineChart.getData().add(series1);

        XYChart.Series series2 = new XYChart.Series();
        series2.getData().add(new XYChart.Data(1, 20));
        series2.getData().add(new XYChart.Data(10, 30));
        series2.getData().add(new XYChart.Data(20, 40));
        lineChart.getData().add(series2);

        XYChart.Series series3 = new XYChart.Series();
        // series3 = series1 + series2
        series3.getData().add(new XYChart.Data(1, 10 + 20));
        series3.getData().add(new XYChart.Data(10, 20 + 30));
        series3.getData().add(new XYChart.Data(20, 30 + 40));
        lineChart.getData().add(series3);



        Scene scene = new Scene(lineChart, 800, 600);
        stage.setScene(scene);
        stage.show();

    }

    public static void main(String[] args) {
        launch(args);
    }
}

更新1 我已经更新了示例代码。如果我运行此代码,则第3序列会对从第1序列或第2序列中添加或删除数据对象作出反应。但是不幸的是,它对更改数据对象的值没有反应。

import javafx.application.Application;
import javafx.collections.ListChangeListener;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.chart.XYChart.Data;
import javafx.stage.Stage;

public class LineChartSample extends Application {

    private static int updateCounter = 1;

    private XYChart.Series<Integer, Integer> series1, series2, series3;

    @Override
    public void start(Stage stage) {

        final NumberAxis xAxis = new NumberAxis();
        final NumberAxis yAxis = new NumberAxis();
        final LineChart<Integer, Integer> lineChart = new LineChart(xAxis, yAxis);

        series1 = new XYChart.Series<>();
        series1.getData().add(new XYChart.Data(1, 10));
        series1.getData().add(new XYChart.Data(10, 20));
        series1.getData().add(new XYChart.Data(20, 30));
        lineChart.getData().add(series1);

        series2 = new XYChart.Series<>();
        series2.getData().add(new XYChart.Data(1, 20));
        series2.getData().add(new XYChart.Data(10, 30));
        series2.getData().add(new XYChart.Data(20, 40));
        lineChart.getData().add(series2);

        series3 = new XYChart.Series<>();
        lineChart.getData().add(series3);
        bindDataSeieses();

        Scene scene = new Scene(lineChart, 800, 600);
        stage.setScene(scene);
        stage.show();

        // update 1
        updateSumSeries();
        // update 2
        series1.getData().remove(0);
        // update 3
        series1.getData().add(new XYChart.Data(1, 50));
        // No update :-(
        series1.getData().get(0).setYValue(200);

    }

    private void bindDataSeieses() {

        series1.getData().addListener((ListChangeListener<Data<Integer, Integer>>) c -> updateSumSeries());
        series2.getData().addListener((ListChangeListener<Data<Integer, Integer>>) c -> updateSumSeries());

    }

    private void updateSumSeries() {

        System.out.println("Update " + updateCounter++);
        // todo enhance to support series of different length
        if (series1.getData().size() != series2.getData().size())
            return;
        series3.getData().clear();
        for (int index = 0; index < series1.getData().size(); index++) {

            int xValue = series1.getData().get(index).getXValue();
            int yValue = series1.getData().get(index).getYValue() + series2.getData().get(index).getYValue();
            series3.getData().add(new Data<>(xValue, yValue));
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}

1 个答案:

答案 0 :(得分:0)

您可以通过向其他两个添加侦听器来实现3ed系列的动态更新:

import javafx.application.Application;
import javafx.collections.ListChangeListener;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.chart.XYChart.Data;
import javafx.stage.Stage;

public class LineChartSample extends Application {

    private  XYChart.Series<Integer, Integer> series1, series2, series3;
    @Override
    public void start(Stage stage) {

        final NumberAxis xAxis = new NumberAxis();
        final NumberAxis yAxis = new NumberAxis();
        final LineChart<Integer, Integer> lineChart = new LineChart(xAxis, yAxis);
        series1 = new XYChart.Series<>();
        series1.getData().add(new XYChart.Data(1, 10));
        series1.getData().add(new XYChart.Data(10, 20));
        series1.getData().add(new XYChart.Data(20, 30));
        lineChart.getData().add(series1);

        series2 = new XYChart.Series<>();
        series2.getData().add(new XYChart.Data(1, 20));
        series2.getData().add(new XYChart.Data(10, 30));
        series2.getData().add(new XYChart.Data(20, 40));
        lineChart.getData().add(series2);

        series3 = new XYChart.Series<>();
        lineChart.getData().add(series3);
        bindDataSeieses();

        Scene scene = new Scene(lineChart, 800, 600);
        stage.setScene(scene);
        stage.show();
    }

    private void bindDataSeieses() {

        series1.getData().addListener((ListChangeListener<Data<Integer, Integer>>) c -> updateSumSeries());
        series2.getData().addListener((ListChangeListener<Data<Integer, Integer>>) c -> updateSumSeries());

        updateSumSeries();
    }

    private void updateSumSeries() {

        //todo enhance to support series of different length
        if(series1.getData().size() != series2.getData().size())
                        throw new IllegalArgumentException("series1 and series2 must be of same length");
        series3.getData().clear();
        for (int index = 0; index < series1.getData().size(); index++){

            int xValue = series1.getData().get(index).getXValue();
            //todo verify series1.getData().get(index).getXValue() == series2.getData().get(index).getXValue()
            int yValue = series1.getData().get(index).getYValue() + series2.getData().get(index).getYValue();
            series3.getData().add(new Data<>(xValue, yValue));
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}

编辑:对更新后的代码的响应:
不需要更新1。 updateSumSeries()由侦听器调用。
更新2使series1.getData().size() != series2.getData().size()为真,因此引发了IllegalArgumentException。注意您的例外情况。

以下代码通过单击按钮进行演示和编辑:

public class LineChartSample extends Application {

    private  XYChart.Series<Integer, Integer> series1, series2, series3;
    @Override
    public void start(Stage stage) {

        final NumberAxis xAxis = new NumberAxis();
        final NumberAxis yAxis = new NumberAxis();
        final LineChart<Integer, Integer> lineChart = new LineChart(xAxis, yAxis);

        series1 = new XYChart.Series<>();

        series1.getData().add(new XYChart.Data(1, 10));
        series1.getData().add(new XYChart.Data(10, 20));
        series1.getData().add(new XYChart.Data(20, 30));
        lineChart.getData().add(series1);

        series2 = new XYChart.Series<>();
        series2.getData().add(new XYChart.Data(1, 20));
        series2.getData().add(new XYChart.Data(10, 30));
        series2.getData().add(new XYChart.Data(20, 40));
        lineChart.getData().add(series2);

        series3 = new XYChart.Series<>();
        lineChart.getData().add(series3);
        bindDataSeieses();

        BorderPane root = new BorderPane(lineChart);
        Button btn = new Button("Add");
        btn.setOnAction(e->series1.getData().set(0, new Data<>(1, 200)));
        root.setBottom(btn);
        Scene scene = new Scene(root, 800, 600);
        stage.setScene(scene);
        stage.show();
    }

    private void bindDataSeieses() {

        series1.getData().addListener((ListChangeListener<Data<Integer, Integer>>) c -> updateSumSeries());
        series2.getData().addListener((ListChangeListener<Data<Integer, Integer>>) c -> updateSumSeries());

        updateSumSeries();
    }

    private void updateSumSeries() {

        //todo enhance to support series of different length
        if(series1.getData().size() != series2.getData().size())
            throw new IllegalArgumentException("series1 and series2 must be of same length");
        series3.getData().clear();
        for (int index = 0; index < series1.getData().size(); index++){

            int xValue = series1.getData().get(index).getXValue();
            //todo verify series1.getData().get(index).getXValue() == series2.getData().get(index).getXValue()
            int yValue = series1.getData().get(index).getYValue() + series2.getData().get(index).getYValue();
            series3.getData().add(new Data<>(xValue, yValue));
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}