Search code examples
javajavafxfxml

How do I handle multiple button in javafx


I have multiple button on an fxml file. By click on any buttons the fxml form that define in onAction will show. The quesion is:

Am I should load all the forms with for example foreach and when the button clicked the proper form just show or it is not neccessary?

If I should load all the forms, I should do it in initialize function?

I'm newbie in JavaFx and don't know what the best way is?

EDIT:

For example when btn1 clicked the form add user will show, when btn2 is clicked the form delete user will show , ...

The question is:

Am I should load add user form and delete user form ,... when the program start and when the for example btn1 clicked the add user form just show or not?

<BorderPane fx:controller="com.project.controller.eventcontroller" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
   <left>
      <VBox  prefHeight="400.0" prefWidth="110.0" style="-fx-background-color: #404040;" BorderPane.alignment="CENTER">
         <children>
            <Button fx:id="btn1" alignment="TOP_LEFT" mnemonicParsing="false" prefHeight="17.0" prefWidth="111.0" text="btn1" />
            <Button fx:id="btn2" alignment="TOP_LEFT" layoutX="10.0" layoutY="10.0" mnemonicParsing="false" prefHeight="17.0" prefWidth="111.0" text="btn2">
               <VBox.margin>
                  <Insets top="12.0" />
               </VBox.margin>
            </Button>
            <Button fx:id="btn3" alignment="TOP_LEFT" layoutX="10.0" layoutY="47.0" mnemonicParsing="false" prefHeight="17.0" prefWidth="111.0" text="btn3">
               <VBox.margin>
                  <Insets top="12.0" />
               </VBox.margin>
            </Button>
            <Button fx:id="btn4" alignment="TOP_LEFT" layoutX="10.0" layoutY="84.0" mnemonicParsing="false" prefHeight="17.0" prefWidth="111.0" text="btn4">
               <VBox.margin>
                  <Insets top="12.0" />
               </VBox.margin>
            </Button>
         </children>
      </VBox>
   </left>
</BorderPane>

Thanks all for help


Solution

  • Recommended Approach

    My advice is:

    1. Define separate action handlers, e.g. edit() and delete(), for each button.
    2. Inject the onAction handlers for each of them into your controller code using the @FXML annotation.
    3. In the FXML, define corresponding onAction="#edit" and onAction="#delete" attributes for your buttons.
    4. In each action handler, load and display new FXML to handle the UI for the actions.

    Yes, you could preload the FXML for the edit and delete actions elsewhere and then just display the corresponding nodes when the edit and delete actions are performed, but I don't advise you do that.

    Example

    Assumes:

    1. You have defined FXML files edit.fxml and delete.fxml for handling the UI for edit and delete functions.
    2. You want the current scene root replaced by the UIs for the actions when the actions are requested.
    3. Your main application class is named MyApp.
    4. The FXML files are located as resources in the same package as the main application class.

    Code snippet for the controller handling the button actions

    @FXML
    private Button editButton;
    
    @FXML
    private Button deleteButton;
    
    @FXML
    private void edit(ActionEvent e) {
        editButton.getScene().setRoot(
            FXMLLoader.load(MyApp.class.getResource("edit.fxml"));
        );  
    }
    
    @FXML
    private void delete(ActionEvent e) {
        deleteButton.getScene().setRoot(
            FXMLLoader.load(MyApp.class.getResource("delete.fxml"));
        );  
    }
    

    FXML snippet to interface with the controller

    <Button fx:id="editButton" text="Edit" onAction="#edit" />
    <Button fx:id="deleteButton" text="Delete" onAction="#delete" />
    

    References

    There are examples of assigning action handlers to buttons defined in FXML in:

    Sharing data

    Use either:

    OR

    For example, you might pass the id of the item to be edited to your editing controller using the passing parameters technique.

    Showing a dialog

    If you want to show a dialog rather than replace the content of the current scene, you do the following:

    @FXML
    private void edit(ActionEvent e) {
        Scene editScene = new Scene(
            FXMLLoader.load(MyApp.class.getResource("edit.fxml"));
        );
    
        Stage owner = (Stage) editButton.getScene().getWindow(); 
    
        Stage editDialog = new Stage();
        editDialog.initOwner(owner);
        editDialog.initModality(Modality.APPLICATION_MODAL);
        editDialog.setScene(editScene); 
        editDialog.showAndWait();
    }
    

    Adjust the stage settings as needed. For this example, we create a modal dialog. Before allowing the user to interact with the rest of the application again, the system will wait until the user finishes interacting with dialog and closes the dialog.

    The above code uses a standard Stage, but you could also use a Dialog class or subclass instead. The Dialog API is a bit more complicated and can be more difficult to use, and I don't demonstrate its usage here.

    Unrelated advice

    • When you assign ID values to things, make them meaningful (not btn1, btn2, btn3, etc).

    • You don't need to assign fx:id values to items you are not injecting into your controller (you can still do so if you feel that it makes your app easier to understand).

    • Assign a meaningful name and proper case for your controller. For example, not com.project.controller.eventcontroller, but instead com.project.ActionMenu, or some other appropriate name depending on the function required in your application domain.

    • As much as possible, use layout panes with layout hints, instead of hardcoding preferred sizes and absolute layout positioning.