JavaFX跨场景数据传递:点击保存后更新前场景TableView
嘿,这个需求在JavaFX里其实有挺直观的实现方案,我给你分享两种常用的思路,你可以根据自己的项目结构来选:
方法一:使用回调接口(Callback)实现数据传递
这种方式的优势是解耦性好,两个场景的控制器只通过回调接口交互,不会直接依赖彼此。
步骤1:定义Product实体类
首先要创建一个包含所需字段的实体类,并且使用JavaFX的Property类型,这样TableView能自动监听数据变化并更新:
import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; import java.time.LocalDate; public class Product { private final StringProperty id = new SimpleStringProperty(); private final StringProperty name = new SimpleStringProperty(); private final ObjectProperty<LocalDate> date = new SimpleObjectProperty<>(); // 构造方法 public Product(String id, String name, LocalDate date) { this.id.set(id); this.name.set(name); this.date.set(date); } // ID相关的getter、setter和Property方法 public String getId() { return id.get(); } public void setId(String id) { this.id.set(id); } public StringProperty idProperty() { return id; } // 产品名称相关方法 public String getName() { return name.get(); } public void setName(String name) { this.name.set(name); } public StringProperty nameProperty() { return name; } // 日期相关方法 public LocalDate getDate() { return date.get(); } public void setDate(LocalDate date) { this.date.set(date); } public ObjectProperty<LocalDate> dateProperty() { return date; } }
步骤2:主场景(带TableView)的控制器实现
在主控制器里初始化TableView,并且在打开表单场景时,传递一个回调函数用于接收新数据:
import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.stage.Stage; import java.io.IOException; import java.util.function.Consumer; public class MainController { @FXML private TableView<Product> productTable; @FXML private TableColumn<Product, String> idCol; @FXML private TableColumn<Product, String> productCol; @FXML private TableColumn<Product, LocalDate> dateCol; private ObservableList<Product> productList = FXCollections.observableArrayList(); public void initialize() { // 绑定表格列与Product的属性 idCol.setCellValueFactory(cellData -> cellData.getValue().idProperty()); productCol.setCellValueFactory(cellData -> cellData.getValue().nameProperty()); dateCol.setCellValueFactory(cellData -> cellData.getValue().dateProperty()); // 给表格设置数据源 productTable.setItems(productList); } // 点击"add Product"按钮的事件处理 @FXML private void openAddProductForm(ActionEvent event) throws IOException { // 加载表单场景的FXML文件 FXMLLoader loader = new FXMLLoader(getClass().getResource("add-product-form.fxml")); Parent root = loader.load(); // 获取表单场景的控制器实例 AddProductController formController = loader.getController(); // 设置回调:当表单点击Save时,将新Product添加到列表 formController.setOnSaveCallback(newProduct -> { productList.add(newProduct); }); // 打开表单窗口 Stage stage = new Stage(); stage.setScene(new Scene(root)); stage.showAndWait(); // 用showAndWait可以阻塞主窗口,直到表单关闭 } }
步骤3:表单场景的控制器实现
在表单控制器里定义回调接口,点击Save按钮时触发回调,将数据传回主场景:
import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.scene.control.Alert; import javafx.scene.control.DatePicker; import javafx.scene.control.TextField; import javafx.stage.Stage; import javafx.scene.Node; import java.time.LocalDate; import java.util.function.Consumer; public class AddProductController { @FXML private TextField idField; @FXML private TextField productNameField; @FXML private DatePicker datePicker; private Consumer<Product> onSaveCallback; // 设置回调的方法 public void setOnSaveCallback(Consumer<Product> callback) { this.onSaveCallback = callback; } // Save按钮的事件处理 @FXML private void handleSave(ActionEvent event) { // 获取输入框数据并做简单校验 String id = idField.getText().trim(); String name = productNameField.getText().trim(); LocalDate date = datePicker.getValue(); if (id.isEmpty() || name.isEmpty() || date == null) { Alert alert = new Alert(Alert.AlertType.WARNING); alert.setTitle("输入错误"); alert.setHeaderText(null); alert.setContentText("请填写所有必填字段!"); alert.showAndWait(); return; } // 创建新的Product对象 Product newProduct = new Product(id, name, date); // 触发回调,将数据传回主控制器 if (onSaveCallback != null) { onSaveCallback.accept(newProduct); } // 关闭表单窗口 Stage stage = (Stage) ((Node) event.getSource()).getScene().getWindow(); stage.close(); } }
方法二:共享ObservableList数据源
如果你的项目中多个场景都需要操作同一组数据,直接共享ObservableList会更直接,TableView会自动监听列表变化并更新。
步骤1:同样定义Product实体类(和方法一完全一致)
步骤2:主场景控制器修改
只需要在打开表单时,把主场景的ObservableList传递给表单控制器:
// 主控制器的openAddProductForm方法修改如下 @FXML private void openAddProductForm(ActionEvent event) throws IOException { FXMLLoader loader = new FXMLLoader(getClass().getResource("add-product-form.fxml")); Parent root = loader.load(); AddProductController formController = loader.getController(); // 直接传递共享的数据源列表 formController.setProductList(productList); Stage stage = new Stage(); stage.setScene(new Scene(root)); stage.showAndWait(); }
步骤3:表单控制器修改
直接操作共享的列表,添加新数据:
import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.scene.control.Alert; import javafx.scene.control.DatePicker; import javafx.scene.control.TextField; import javafx.collections.ObservableList; import javafx.stage.Stage; import javafx.scene.Node; import java.time.LocalDate; public class AddProductController { @FXML private TextField idField; @FXML private TextField productNameField; @FXML private DatePicker datePicker; private ObservableList<Product> productList; // 设置共享列表的方法 public void setProductList(ObservableList<Product> productList) { this.productList = productList; } @FXML private void handleSave(ActionEvent event) { // 同样的输入校验逻辑 String id = idField.getText().trim(); String name = productNameField.getText().trim(); LocalDate date = datePicker.getValue(); if (id.isEmpty() || name.isEmpty() || date == null) { Alert alert = new Alert(Alert.AlertType.WARNING); alert.setTitle("输入错误"); alert.setHeaderText(null); alert.setContentText("请填写所有必填字段!"); alert.showAndWait(); return; } Product newProduct = new Product(id, name, date); // 直接添加到共享列表,主场景的TableView会自动更新 productList.add(newProduct); // 关闭窗口 Stage stage = (Stage) ((Node) event.getSource()).getScene().getWindow(); stage.close(); } }
额外注意事项
- 确保你的FXML文件中,所有控件都正确设置了
fx:id(比如主场景的TableView的fx:id是productTable,表单的TextField是idField等),并且按钮的onAction属性绑定到对应的处理方法。 - 使用JavaFX的
Property类型是关键,这样TableView才能自动响应数据变化,不需要手动调用refresh()方法。
内容的提问来源于stack exchange,提问作者Toolmaker
相关产品推荐
相关产品推荐

