1

Currently I have a main controller which controls adding elements to a Border Pane's left pane for navigation and center pane for content. I am also using fx:root to load new FXML layouts, each with a separate controller into the center pane of the Border Pane. Trying to call the setCenter method of the MainController from a center pane controller my center pane is not updated. I'm guessing the newly created controller is not being associated with the mainPane in the main Controller. How do I associate them?

Main Ctonroller

This loads both the center and left panes with the appropriate views and associated controllers using either button.

    public class MainController {

    @FXML
    BorderPane mainPane;
    @FXML
    Button orderBtn, adminBtn;
    @FXML
    static
    Label statusTxt;

    public void initialize(){

        orderBtn.setOnAction(event -> {
           setCenter(new ControllerConnector("/view/OrderView.fxml"));
           setNav(new ControllerConnector("/view/OrderNav.fxml"));
        });

        adminBtn.setOnAction(event -> {
           setCenter(new ControllerConnector("/view/ProductView.fxml"));
           setNav(new ControllerConnector("/view/AdminNav.fxml"));
        });

    public static void updateStatus(String string) {
        statusTxt.setText(string);
    }

    public void setCenter(ControllerConnector connector){
        this.mainPane.setCenter(connector);
    }

    public void setNav(ControllerConnector connector){
        this.mainPane.setLeft(connector);
    }
}

Product Controller

The search function works in this controller which is loaded from the associated view so I know the controller was initialized. When the newBtn is clicked nothing happens.

public class ProductController {
    @FXML
    TableView<Product> productTable;
    @FXML
    TableColumn prodCol, sizeCol, categoryCol, priceCol;
    @FXML
    TextField searchTxt;
    @FXML
    Button searchBtn, newBtn, editBtn, deleteBtn;

    public void initialize() throws SQLException {
        ObservableList<Product> products = ProductDAO.getProducts();
        prodCol.setCellValueFactory(new PropertyValueFactory<Product, String>("name"));
        sizeCol.setCellValueFactory(new PropertyValueFactory<Product, String>("size"));
        priceCol.setCellValueFactory(new PropertyValueFactory<Product, Double>("price"));
        categoryCol.setCellValueFactory(new PropertyValueFactory<Product, String>("category"));
        productTable.setItems(products);

        searchBtn.setOnAction(event -> {
            ObservableList<Product> searchProducts = FXCollections.observableArrayList();
            String searchString = searchTxt.getText();
            for (Product product : products) {
                if(product.getName().contains(searchString) || product.getSize().contains(searchString)){
                    searchProducts.add(product);
                }
            }
            products.removeAll(products);
            products.addAll(searchProducts);

        });

        searchTxt.setOnMouseClicked(event -> {
            products.removeAll(products);
            try {
                products.addAll(ProductDAO.getProducts());
            } catch (SQLException exception) {
                exception.printStackTrace();
            }
        });

        newBtn.setOnAction(event -> {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("/view/MainView.fxml"));
            try {
                loader.load();
            } catch (IOException e) {
                e.printStackTrace();
            }
            MainController mainController = loader.getController();
            mainController.setCenter(new ControllerConnector("/view/NewProductView.fxml"));
        });
    }
}

ControllerConnector

Using this class to create a Node to pass into the Border Pane set mehtods.

public class ControllerConnector extends GridPane {

    public ControllerConnector(String fxmlPath){
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource(fxmlPath));
        fxmlLoader.setRoot(this);
        try{
            fxmlLoader.load();
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}
Chris R.
  • 11
  • 2
  • 1
    Your `newBtn` event handler loads the main FXML again, creating a whole new instance of the UI defined in the FXML file. You change the center of *that* UI, which is never displayed, so you never see any changes. You need a reference to the *existing* controller. The quick-and-dirty way to do this is just to [pass a reference](https://stackoverflow.com/questions/14187963/passing-parameters-javafx-fxml) to the main controller to the `ProductController`. – James_D Aug 22 '20 at 15:36
  • @James_D, how do you get the existing loader? I see in the example you linked https://stackoverflow.com/a/51050736/14148325, that there is a way to pass the MainController to the ProdController, but each of these do this through creation of a new loader. The loader to load the ProdController is actually done in the ControllerConnector. Do I just add to the ControllerConnector constructor to take the MainController and pass it around? – Chris R. Aug 22 '20 at 18:23
  • You have to get it when you originally load the main fxml. – James_D Aug 22 '20 at 18:24

0 Answers0