You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在图表右侧创建展示xSpin与ySpin值的表格?

在图表右侧添加数据表格的实现方案

要在图表右侧展示xSpin和ySpin输入的x、y值,用JavaFX的TableView是最适配的选择——它能直接绑定数据集合,和图表的XYSeries同步更新,比手动维护GridPane文本框更高效可靠。

实现步骤

  • 定义数据模型类DataPoint,封装x、y值,用JavaFX属性类型实现双向绑定
  • 创建ObservableList<DataPoint>作为表格数据源,与XYSeries联动更新
  • 配置TableView的两列,分别对应x、y值的显示
  • 将TableView嵌入布局的右侧区域,调整窗口尺寸适配显示

修改后的完整代码

package Grava;

import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.ToolBar;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.data.statistics.Regression;
import org.jfree.fx.ChartViewer;

public class ScatterAdd extends Application {

    private final XYSeries series = new XYSeries("Voltage");
    private final XYSeries trend = new XYSeries("Trend");
    private final XYSeriesCollection dataset = new XYSeriesCollection(series);
    // 表格数据源,存储所有输入的x、y值
    private final ObservableList<DataPoint> dataPoints = FXCollections.observableArrayList();

    ChoiceBox<String> domainLabels = new ChoiceBox<>();
    ChoiceBox<String> rangeLabels = new ChoiceBox<>();

    // 数据模型类,封装x、y值
    public static class DataPoint {
        private final DoubleProperty x = new SimpleDoubleProperty();
        private final DoubleProperty y = new SimpleDoubleProperty();

        public DataPoint(double x, double y) {
            this.x.set(x);
            this.y.set(y);
        }

        public double getX() {
            return x.get();
        }

        public DoubleProperty xProperty() {
            return x;
        }

        public double getY() {
            return y.get();
        }

        public DoubleProperty yProperty() {
            return y;
        }
    }

    private JFreeChart createChart() {
        return ChartFactory.createScatterPlot("VI Characteristics", "Current", "Voltage", dataset);
    }

    @Override
    public void start(Stage stage) {
        Image image = new Image("Grava.logo.png");
        stage.getIcons().add(image);
        var chart = createChart();

        XYPlot plot = chart.getXYPlot();
        plot.setDomainCrosshairVisible(true);
        plot.setRangeCrosshairVisible(true);
        XYLineAndShapeRenderer r = (XYLineAndShapeRenderer) plot.getRenderer();
        r.setSeriesLinesVisible(1, Boolean.TRUE);
        r.setSeriesShapesVisible(1, Boolean.FALSE);

        var equation = new TextField();
        series.addChangeListener((event) -> {
            if (series.getItemCount() > 1) {
                double[] coefficients = Regression.getOLSRegression(dataset, 0);
                double b = coefficients[0]; // 截距
                double m = coefficients[1]; // 斜率
                equation.setText("y = " + m + " x + " + b);
                double x = series.getDataItem(0).getXValue();
                trend.clear();
                trend.add(x, m * x + b);
                x = series.getDataItem(series.getItemCount() - 1).getXValue();
                trend.add(x, m * x + b);
                // 避免重复添加趋势线
                if (!dataset.getSeries().contains(trend)) {
                    dataset.addSeries(trend);
                }
            }
        });

        domainLabels.getSelectionModel().selectedItemProperty().addListener((ov, s0, s1) -> {
            chart.getXYPlot().getDomainAxis().setLabel(s1);
        });
        rangeLabels.getSelectionModel().selectedItemProperty().addListener((ov, s0, s1) -> {
            chart.getXYPlot().getRangeAxis().setLabel(s1);
        });

        domainLabels.getItems().addAll("Current", "Seconds");
        domainLabels.setValue("Current");

        rangeLabels.getItems().addAll("Voltage", "Metres");
        rangeLabels.setValue("Voltage");

        var xSpin = new Spinner<Double>(-10000000.000, 10000000.000, 0, 0.1);
        xSpin.setEditable(true);
        xSpin.setPromptText("Xvalue");

        var ySpin = new Spinner<Double>(-10000000.000, 10000000.000, 0, 0.1);
        ySpin.setEditable(true);
        ySpin.setPromptText("Yvalue");

        var button = new Button("Add");
        button.setOnAction(ae -> {
            double xVal = xSpin.getValue();
            double yVal = ySpin.getValue();
            // 同时添加到图表series和表格数据源
            series.add(xVal, yVal);
            dataPoints.add(new DataPoint(xVal, yVal));
        });

        HBox xBox = new HBox();
        xBox.getChildren().addAll(domainLabels);

        HBox yBox = new HBox();
        yBox.getChildren().addAll(rangeLabels);

        var enter = new ToolBar(xBox, xSpin, yBox, ySpin, button, equation);
        BorderPane.setAlignment(enter, Pos.CENTER);

        // 配置表格
        TableView<DataPoint> tableView = new TableView<>(dataPoints);
        tableView.setPrefWidth(200);

        // 创建x列
        TableColumn<DataPoint, Double> xColumn = new TableColumn<>("X值");
        xColumn.setCellValueFactory(cellData -> cellData.getValue().xProperty().asObject());
        xColumn.setPrefWidth(100);

        // 创建y列
        TableColumn<DataPoint, Double> yColumn = new TableColumn<>("Y值");
        yColumn.setCellValueFactory(cellData -> cellData.getValue().yProperty().asObject());
        yColumn.setPrefWidth(100);

        tableView.getColumns().addAll(xColumn, yColumn);

        BorderPane root = new BorderPane();
        root.setCenter(new ChartViewer(chart));
        root.setBottom(enter);
        root.setRight(tableView); // 将表格放到右侧

        stage.setTitle("ScatterAdd");
        stage.setScene(new Scene(root, 920, 480)); // 调整窗口宽度,容纳表格
        stage.show();
    }

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

关键说明

  1. 数据模型DataPoint:用JavaFX的DoubleProperty实现属性绑定,表格能自动感知数据变化并更新
  2. 同步更新逻辑:点击Add按钮时,同时把值添加到XYSeries和ObservableList<DataPoint>,保证图表与表格数据完全一致
  3. 布局适配:将TableView放到BorderPane的right区域,同时调整窗口宽度确保表格完整显示
  4. 趋势线优化:添加判断逻辑避免重复将趋势线添加到数据集,防止图表异常

内容的提问来源于stack exchange,提问作者armitageshanks99

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 02:05:20