Joulin Nicolas
Joulin Nicolas

Reputation: 257

What is the FXMLLoader load method really doing?

I have this javaFX interface consisting of a root layout which is a simple BorderPane. And two AnchorPane which I want to alternatively set in the center of the rootLayout when a button is pushed on the rootLayout menu. It's working alright but there is one thing I'm having trouble to understand. I am calling a method with the rootlayout controller when the button is pushed. And although it should only be executed once it is executed twice !

To give the basic idea, here's what the code involved look like :

method handling the button action, located in the root layout controller :

@FXML
private void handleStockWizardButton(){
    mainApp.updateProduct(0,10);
    mainApp.showStockWizard();
}

It's filling an Observable list which is later passed to the second page controller in order to display them in a table view. the method to display this view and set every thing is the following :

public void showStockWizard(){
    try {
        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(MainApp.class.getResource("view/StockWizard.fxml"));
        AnchorPane StockWizard = (AnchorPane) loader.load();
        rootLayout.setCenter(StockWizard);
        StockWizardController controller = loader.getController();
        controller.setMainApp(this);
        controller.setProduct(product);
    } catch (IOException e){
        e.printStackTrace();
    }
}

what is bothering me here is that on the loader.load() call the handleStockWizardButton() method, although not related to the constructor present here, is called! Is there some aspect of the load method I am missing ?

EDIT :

Here are some more code involved :

controller of the view to display, setting some value factories and set some listener, nothing that should send back to the root controller :

@FXML
private void initialize(){
    productNameColumn.setCellValueFactory(CellData -> CellData.getValue().nameProperty());
    productReferenceColumn.setCellValueFactory(CellData -> CellData.getValue().referenceProperty());
    productUnitSellingPriceColumn.setCellValueFactory(CellData -> CellData.getValue().unitSellingPriceProperty());
    displayChoices.add("10");
    displayChoices.add("25");
    displayChoices.add("50");
    displayChoiceBox.setItems(displayChoices);
    displayChoiceBox.setValue("10");
    displayChoiceBox.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> setDisplayValue());
    currentPage.setText("1");
}

The details of the updateproducts methods would be of no use here since it's just accessing a web service and processing the lines recieved. it is quite clean.

Here is the FXML file for the rootlayout borderPane, what is to notice here is the menu item that calls handleButton on action :

<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.BorderPane?>

<BorderPane minHeight="540.0" prefHeight="720.0" prefWidth="1280.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="prestashopwebservice.view.RootController">
   <top>
      <MenuBar BorderPane.alignment="CENTER">
        <menus>
          <Menu mnemonicParsing="false" onAction="#handleConfigure" text="Configuration">
               <items>
                  <MenuItem mnemonicParsing="false" onAction="#handleConfigure" text="open configuration" />
               </items></Menu>
            <Menu mnemonicParsing="false" onAction="#handleStockWizard" text="StockWizard">
               <items>
                  <MenuItem mnemonicParsing="false" onAction="#handleStockWizardButton" text="open StockWizard" />
               </items></Menu>
        </menus>
      </MenuBar>
   </top>
</BorderPane>

Upvotes: 2

Views: 1011

Answers (1)

fabian
fabian

Reputation: 82521

The onAction event will be propagated up through the menu structure, unless consumed. Therefore if you click the open configuration MenuItem and handleConfigure doesn't consume the event, it will be triggered again for the Configuration Menu.

Prevent this by calling Event.consume in the handler methods, e.g.

@FXML
private void handleConfigure(ActionEvent evt) {
    ...

    evt.consume();
}

or simply remove the onAction attributes from the Menus (they could be replaced with onShown or onHidden, if necessary).

Upvotes: 2

Related Questions