首页 > 解决方案 > 如何从其他两个系列中获得一个系列?

问题描述

我正在 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);
    }
}

标签: javajavafxchartsbindingseries

解决方案


您可以通过向另外两个添加侦听器来实现 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()由侦听器调用。
更新 2series1.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);
    }
} 

推荐阅读