Search code examples
java-8javafx-2fxml

JavaFX pass values from child to parent


I have one parent controller which contain one button. When I click on button it open new window and show some data into table. The code I have used for opening window is

            Stage stage = new Stage();
            FXMLLoader fxmlLoader = new FXMLLoader(
                    getClass().getResource("../layout/SearchCustomer.fxml"));
            Parent parent = (Parent) fxmlLoader.load();
            Scene scene = new Scene(parent);
            stage.initModality(Modality.APPLICATION_MODAL);
            stage.initOwner(parent.getScene().getWindow());
            stage.setScene(scene);
            stage.resizableProperty().setValue(false);
            stage.showAndWait();

It opens window properly. Now what I need is, when I double click on the row of table of the child window, It should set some value in parent controller textbox. How would we pass this value from child controller to parent controller?


Solution

  • Expose a property in your child controller and observe it from the "parent" controller. There isn't really enough information in your question to give a precise answer, but it would look something like:

    public class ChildController {
    
        @FXML
        private TableView<Customer> customerTable ;
    
        private final ReadOnlyObjectWrapper<Customer> currentCustomer = new ReadOnlyObjectWrapper<>();
    
        public ReadOnlyObjectProperty<Customer> currentCustomerProperty() {
            return currentCustomer.getReadOnlyProperty() ;
        }
    
        public Customer getCurrentCustomer() {
            return currentCustomer.get();
        }
    
        public void initialize() {
            // set up double click on table:
    
            customerTable.setRowFactory(tv -> {
                TableRow<Customer> row = new TableRow<>();
                row.setOnMouseClicked(e -> {
                    if (row.getClickCount() == 2 && ! row.isEmpty()) {
                        currentCustomer.set(row.getItem());
                    }
                }
            });
    
        }
    }
    

    and then you just do:

    Stage stage = new Stage();
    FXMLLoader fxmlLoader = new FXMLLoader(
            getClass().getResource("../layout/SearchCustomer.fxml"));
    Parent parent = (Parent) fxmlLoader.load();
    
    ChildController childController = fxmlLoader.getController();
    childController.currentCustomerProperty().addListener((obs, oldCustomer, newCustomer) -> {
        // do whatever you need with newCustomer....
    });
    
    Scene scene = new Scene(parent);
    stage.initModality(Modality.APPLICATION_MODAL);
    stage.initOwner(parent.getScene().getWindow());
    stage.setScene(scene);
    stage.resizableProperty().setValue(false);
    stage.showAndWait();
    

    An alternative approach is to use a Consumer as a callback in the child controller:

    public class ChildController {
    
        @FXML
        private TableView<Customer> customerTable ;
    
        private Consumer<Customer> customerSelectCallback ;
    
        public void setCustomerSelectCallback(Consumer<Customer> callback) {
            this.customerSelectCallback = callback ;
        }
    
        public void initialize() {
            // set up double click on table:
    
            customerTable.setRowFactory(tv -> {
                TableRow<Customer> row = new TableRow<>();
                row.setOnMouseClicked(e -> {
                    if (row.getClickCount() == 2 && ! row.isEmpty()) {
                        if (customerSelectCallback != null) {
                            customerSelectCallback.accept(row.getItem());
                        }
                    }
                }
            });
    
        }
    }
    

    And in this version you do

    Stage stage = new Stage();
    FXMLLoader fxmlLoader = new FXMLLoader(
            getClass().getResource("../layout/SearchCustomer.fxml"));
    Parent parent = (Parent) fxmlLoader.load();
    
    ChildController childController = fxmlLoader.getController();
    childController.setCustomerSelectCallback(customer -> {
        // do whatever you need with customer....
    });
    
    Scene scene = new Scene(parent);
    stage.initModality(Modality.APPLICATION_MODAL);
    stage.initOwner(parent.getScene().getWindow());
    stage.setScene(scene);
    stage.resizableProperty().setValue(false);
    stage.showAndWait();