JavaFX:如何在同一界面的两个TableView加载同一模型类数据
问题:同一Controller下两个TableView的复用配置方案
我在同一个界面有两个TableView(tableA和tableB),共用同一个Controller,FXML注入代码如下:
@FXML TableView <Product> tableA; @FXML TableView <Product> tableB;
我想不用重复代码,就能给两个TableView添加相同数据,同时需要初始化所有TableColumn(不确定能不能跳过初始化),初始化代码示例如下:
productName.setCellValueFactory(new PropertyValueFactory<Product, String>("productName")); price.setCellValueFactory(new PropertyValueFactory<Product, Double>("price")); /* ... */
想请教两个问题:
- 有没有通过ID(
tableA、tableB)访问数据的解决方案? - 是否必须为每个TableColumn设置ID?
当前Controller代码:
@FXML TableView <Product> tableA; @FXML TableView <Product> tableB; @FXML TableColumn <Product, String> productName; @FXML TableColumn <Product, Double> price; @FXML TableColumn <Product, Integer> quantity; ObservableList<Product> tableData; private void intializeTableColumns() { tableData = FXCollections.observableArrayList(); productName.setCellValueFactory(new PropertyValueFactory<Product, String>("productName")); price.setCellValueFactory(new PropertyValueFactory<Product, Double>("price")); quantity.setCellValueFactory(new PropertyValueFactory<Product, Integer>("quantity")); } private void insertInTableData() { Product product = new Product(); /* ...*/ tableData.addAll(product); /*Add data in both tables */ tableA.setItems(tableData); tableB.setItems(tableData); }
当前FXML代码:
<TableView fx:id="tableA" prefHeight="200.0" styleClass="table-2"> <columns> <TableColumn maxWidth="-Infinity" minWidth="50.0" prefWidth="50.0" text="N°" /> <TableColumn prefWidth="75.0" text="Product" /> <TableColumn prefWidth="75.0" text="Price" /> <TableColumn prefWidth="75.0" text="Quantity" /> </columns> <columnResizePolicy><TableView fx:constant="CONSTRAINED_RESIZE_POLICY" /></columnResizePolicy> </TableView> <TableView fx:id="tableB" prefHeight="200.0" styleClass="table-2"> <columns> <TableColumn maxWidth="-Infinity" minWidth="50.0" prefWidth="50.0" text="N°" /> <TableColumn prefWidth="75.0" text="Product" /> <TableColumn minWidth="-Infinity" prefWidth="75.0" text="Price" /> <TableColumn minWidth="-Infinity" prefWidth="75.0" text="Quantity" /> </columns> <columnResizePolicy><TableView fx:constant="CONSTRAINED_RESIZE_POLICY" /></columnResizePolicy> </TableView>
解决方案
1. 通过ID访问数据的方案
完全可以实现。你可以将两个TableView放入集合,通过循环统一配置,避免重复代码。数据层面,直接共用同一个ObservableList即可(你当前代码已经这么做了,这是最优解——因为ObservableList是双向绑定的,数据变更会自动同步到两个表格,无需额外维护)。
2. 是否必须为每个TableColumn设置ID?
不是必须的。如果想通过FXML将列注入到Controller,才需要给列设置fx:id;如果不想设置ID,可以在Controller中动态创建并配置TableColumn,再添加到对应TableView中,这种方式更灵活,还能避免重复配置。
优化后的代码示例
方案一:动态创建TableColumn(无需修改FXML)
这种方式不用改动现有FXML,直接在Controller中统一配置两个表格的列:
@FXML TableView<Product> tableA; @FXML TableView<Product> tableB; ObservableList<Product> tableData; @Override public void initialize() { // 初始化共用数据集合 tableData = FXCollections.observableArrayList(); // 统一配置两个表格 configureTable(tableA); configureTable(tableB); // 插入测试数据 insertInTableData(); } // 通用表格配置方法 private void configureTable(TableView<Product> tableView) { // 创建序号列(非Product属性,需自定义CellFactory) TableColumn<Product, Integer> indexColumn = new TableColumn<>("N°"); indexColumn.setMaxWidth(Double.MAX_VALUE); indexColumn.setMinWidth(50.0); indexColumn.setPrefWidth(50.0); indexColumn.setCellFactory(col -> new TableCell<>() { @Override protected void updateItem(Integer item, boolean empty) { super.updateItem(item, empty); setText(empty ? null : String.valueOf(getIndex() + 1)); } }); // 创建产品名列 TableColumn<Product, String> productNameCol = new TableColumn<>("Product"); productNameCol.setPrefWidth(75.0); productNameCol.setCellValueFactory(new PropertyValueFactory<>("productName")); // 创建价格列 TableColumn<Product, Double> priceCol = new TableColumn<>("Price"); priceCol.setPrefWidth(75.0); priceCol.setCellValueFactory(new PropertyValueFactory<>("price")); // 创建数量列 TableColumn<Product, Integer> quantityCol = new TableColumn<>("Quantity"); quantityCol.setPrefWidth(75.0); quantityCol.setCellValueFactory(new PropertyValueFactory<>("quantity")); // 将列添加到表格 tableView.getColumns().addAll(indexColumn, productNameCol, priceCol, quantityCol); // 设置列调整策略 tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); // 绑定数据集合 tableView.setItems(tableData); } private void insertInTableData() { // 添加测试数据 tableData.addAll( new Product("Product 1", 19.99, 5), new Product("Product 2", 29.99, 3) ); }
方案二:给FXML列设ID,批量注入配置
如果想保留FXML的列定义,需要给每个表格的列设置唯一fx:id,修改后的FXML如下:
<TableView fx:id="tableA" prefHeight="200.0" styleClass="table-2"> <columns> <TableColumn fx:id="tableAIndex" maxWidth="-Infinity" minWidth="50.0" prefWidth="50.0" text="N°" /> <TableColumn fx:id="tableAProductName" prefWidth="75.0" text="Product" /> <TableColumn fx:id="tableAPrice" prefWidth="75.0" text="Price" /> <TableColumn fx:id="tableAQuantity" prefWidth="75.0" text="Quantity" /> </columns> <columnResizePolicy><TableView fx:constant="CONSTRAINED_RESIZE_POLICY" /></columnResizePolicy> </TableView> <TableView fx:id="tableB" prefHeight="200.0" styleClass="table-2"> <columns> <TableColumn fx:id="tableBIndex" maxWidth="-Infinity" minWidth="50.0" prefWidth="50.0" text="N°" /> <TableColumn fx:id="tableBProductName" prefWidth="75.0" text="Product" /> <TableColumn fx:id="tableBPrice" minWidth="-Infinity" prefWidth="75.0" text="Price" /> <TableColumn fx:id="tableBQuantity" minWidth="-Infinity" prefWidth="75.0" text="Quantity" /> </columns> <columnResizePolicy><TableView fx:constant="CONSTRAINED_RESIZE_POLICY" /></columnResizePolicy> </TableView>
对应的Controller代码:
@FXML TableView<Product> tableA; @FXML TableView<Product> tableB; @FXML TableColumn<Product, Integer> tableAIndex; @FXML TableColumn<Product, String> tableAProductName; @FXML TableColumn<Product, Double> tableAPrice; @FXML TableColumn<Product, Integer> tableAQuantity; @FXML TableColumn<Product, Integer> tableBIndex; @FXML TableColumn<Product, String> tableBProductName; @FXML TableColumn<Product, Double> tableBPrice; @FXML TableColumn<Product, Integer> tableBQuantity; ObservableList<Product> tableData; @Override public void initialize() { tableData = FXCollections.observableArrayList(); // 批量配置两个表格的列 configureColumns(tableAIndex, tableAProductName, tableAPrice, tableAQuantity); configureColumns(tableBIndex, tableBProductName, tableBPrice, tableBQuantity); // 绑定数据 tableA.setItems(tableData); tableB.setItems(tableData); insertInTableData(); } private void configureColumns(TableColumn<Product, Integer> indexCol, TableColumn<Product, String> nameCol, TableColumn<Product, Double> priceCol, TableColumn<Product, Integer> quantityCol) { // 配置序号列 indexCol.setCellFactory(col -> new TableCell<>() { @Override protected void updateItem(Integer item, boolean empty) { super.updateItem(item, empty); setText(empty ? null : String.valueOf(getIndex() + 1)); } }); // 配置属性绑定列 nameCol.setCellValueFactory(new PropertyValueFactory<>("productName")); priceCol.setCellValueFactory(new PropertyValueFactory<>("price")); quantityCol.setCellValueFactory(new PropertyValueFactory<>("quantity")); } private void insertInTableData() { tableData.addAll( new Product("Product 1", 19.99, 5), new Product("Product 2", 29.99, 3) ); }
关键说明
- 两个表格共用同一个
ObservableList是最优解,数据变更会自动同步,无需额外维护。 - 动态创建列的方式更简洁,避免了FXML中大量重复的列定义,也不用维护一堆列的
fx:id。 - 序号列不属于Product的属性,因此需要自定义
CellFactory来显示行号,这部分逻辑可以封装复用。
内容的提问来源于stack exchange,提问作者Nacira
相关产品推荐
相关产品推荐

