如何在 JavaFX 中将简单的双矩阵绘制到 TableView 中?

Giu*_*rdo 1 java javafx tableview

我想TableView在 JavaFX 中创建一个简单的数据,其中我的数据是一个类似矩阵的二维double[][]数组,但我不知道如何实现这一点,有什么建议吗?

jew*_*sea 5

正如 Fabian 在评论中建议的那样:

  1. 将您的表定义为:

    TableView<double[]>
    
    Run Code Online (Sandbox Code Playgroud)
  2. 将数组的元素double[][]作为项目添加到表中(从 中提取元素double[][]并将它们添加到 中ObservableList<double[]>)。

  3. 为表创建列,为每个列提供一个单元格值工厂。

    col.setCellValueFactory(param -> new ReadOnlyObjectWrapper<>(param.getValue()[c]))
    
    Run Code Online (Sandbox Code Playgroud)

    其中c是列索引。

  4. 如果您需要格式化单元格项目,还需要提供单元格工厂

矩阵

import javafx.application.Application;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.stage.Stage;

import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class MatrixTable extends Application {
    private Random random = new Random(42);
    private static final int N_COLS = 4;
    private static final int N_ROWS = 100;
    private static final int MAX_DATA_VALUE = 100;

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

    @Override
    public void start(Stage stage) {
        ObservableList<double[]> data = generateData();

        TableView<double[]> table = new TableView<>(data);
        table.getColumns().setAll(createColumns());
        table.setPrefSize(200, 250);

        stage.setScene(new Scene(table));
        stage.show();
    }

    private ObservableList<double[]> generateData() {
        return FXCollections.observableArrayList(
                IntStream.range(0, N_ROWS)
                        .mapToObj(r ->
                                IntStream.range(0, N_COLS)
                                        .mapToDouble(c -> randomValue())
                                        .toArray()
                        ).collect(Collectors.toList())
        );
    }

    private List<TableColumn<double[], Double>> createColumns() {
        return IntStream.range(0, N_COLS)
                .mapToObj(this::createColumn)
                .collect(Collectors.toList());
    }

    private TableColumn<double[], Double> createColumn(int c) {
        TableColumn<double[], Double> col = new TableColumn<>("C" + (c + 1));
        col.setCellValueFactory(param -> new ReadOnlyObjectWrapper<>(param.getValue()[c]));

        return col;
    }

    private long randomValue() {
        return Math.round(random.nextDouble() * MAX_DATA_VALUE  * 100) / 100.0;
    }
}
Run Code Online (Sandbox Code Playgroud)

你能解释一下这行代码吗?

col.setCellValueFactory(param -> new ReadOnlyObjectWrapper<>(param.getValue()[c]))
Run Code Online (Sandbox Code Playgroud)

来自javadoc

需要设置单元格值工厂来指定如何填充单个 TableColumn 中的所有单元格。单元格值工厂是提供 TableColumn.CellDataFeatures 实例的回调,并期望返回 ObservableValue。

所以它所做的是定义一种从行数据数组中提取列数据的方法double[](已由 提供param.getValue())。因为我们在数据值周围使用 ReadOnlyObjectWrapper 所以如果您使表格单元格可编辑(我在本示例中没有这样做),它不会将编辑后的值写回数组。包装器是将双精度数据值转换为 ObservableValue 所必需的(根据单元工厂接口的要求)。

是的,我知道这很令人困惑,但这就是让 TableView 能够有效地得到潜在数百万数据项作为虚拟化控件的支持所付出的代价。如果您不需要 TableView 的虚拟化功能和其他功能,您始终可以只使用 GridPane 中的标签