【问题标题】:How to get a series from two other series?如何从其他两个系列中获得一个系列?
【发布时间】:2026-01-25 15:55:01
【问题描述】:

我正在 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 或 2 的值发生更改(添加、删除、更改等),系列 3 应该会自动更新。
  • 你是如何修改数据的?
  • 实际上我通过拖动图表中绘制的系列的节点来更改数据。示例代码中并没有让它尽可能简单。
  • 在回答问题后修改问题不是一个好习惯。

标签: java javafx charts binding series


【解决方案1】:

另外两个监听器可以实现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);
    }
} 

【讨论】:

  • 非常感谢您的回答。系列 3 对从系列 1 和 2 中添加和删除数据做出反应。我如何管理系列 3 也对数据对象的更改做出反应(例如 series1.getData().get(0).setYValue(200))。
  • 确实如此。 series1series2 注册了 ListChangeListenerListChangeListener 响应编辑以及添加和删除。
  • 亲爱的 c0der,感谢您的耐心等待。我稍微修改了代码。不幸的是它对我不起作用?你知道问题可能是什么吗?
  • 查看我编辑的答案。不建议在回答后更改问题,因为这会使答案变得无关紧要或不完整。如有新问题,请发新帖。
  • 亲爱的 c0der。更新应该在 series1.getData().get(0).setYValue(200) 之后调用;但它没有被调用。