Search code examples
javafxmodel-view-controllernullpointerexceptioncontrollerfxml

JavaFX NullpointerException with FXML in own dialogbox when trying to close window


I am new to JavaFX. I programmed a tableview with a list of persons with their address. Everything worked fine. Then I wanted to write it in the MVC or even better the MVP Design pattern. I am working with FXML and scenebuilder to layout the scenes. Now with the MVC I have the problem that I get a NUllpointerException when i.e. I wanna close the confirm dialog box. And I also can't change the labeltext for the confirmdialog window scene. I think I know what the problem is but don't know how to solve this properly. The controller gets instantiated twice and therefore the first values of the variables form the fxml are NUll.

So this is how I wrote my little app:

MiniTest.java - my main App


package AddressBook;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class MiniTest extends Application {

    private static Stage window;

    @Override
    public void start(Stage primaryStage) throws Exception {

        window = primaryStage;
        window.setTitle("Adresslist of Clients");
        Model model = new Model();

        try {
            FXMLLoader mainViewloader = new FXMLLoader(getClass().getResource("View.fxml"));
            Parent root = (Parent) mainViewloader.load();
            MainController mainController = mainViewloader.<MainController>getController();

            window.setScene(new Scene(root));
            window.show();

        } catch (Exception e) {

            e.printStackTrace();
        }
    }

    public static Stage getPrimaryStage() {

        return window;
    }

    public static void main(String[] args) {

        launch(args);
    }
}

Model.java - this is my model, not sure if the content has to be in here. For the next step I wanna collect the data from a mysql db and save it to the db. For now I have the persons like this.

package AddressBook;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

public class Model {

    public ObservableList<Person> getPerson() {

        ObservableList<Person> personList = FXCollections.observableArrayList();

        Address addressPerson1 = new Address("Jaguarweg 12", "23454", "Bensheim");
        Address addressPerson2 = new Address("Friedrich-Ebert-Str. 134", "82635", "Berlin");
        Address addressPerson3 = new Address("Adam-Opel-Str. 1", "92364", "Bamberg");
        Address addressPerson4 = new Address("Power-Shell-Pfad 21", "10083", "Hamburg");
        Address addressPerson5 = new Address("Schwertstr. 76", "749236", "Stuttgart");
        Address addressPerson6 = new Address("Hans-Jacob-Weg 4", "66396", "Wiesbaden");
        Address addressPerson7 = new Address("Georg-Lucas-Str. 110", "53421", "Wien");
        Address addressPerson8 = new Address("Andalusienweg 17", "723612", "Ostfildern");
        Address addressPerson9 = new Address("Mercedes-Benz-Str. 9", "883621", "Wolfsburg");
        Address addressPerson10 = new Address("Heinrich-Schwein-Str. 43", "134923", "Frankfurt");
        Address addressPerson11 = new Address("Engel-Teufel-Str. 66", "083273", "Hildesheim");

        personList.add(new Person("Georg Sorresto", addressPerson1));
        personList.add(new Person("Flynn Bozzen", addressPerson2));
        personList.add(new Person("Bill Klang", addressPerson3));
        personList.add(new Person("Wilhelm Busch", addressPerson4));
        personList.add(new Person("Gertrud Raven", addressPerson5));
        personList.add(new Person("Markus Berg", addressPerson6));
        personList.add(new Person("Juergen Schmidt", addressPerson7));
        personList.add(new Person("Fritz Titz", addressPerson8));
        personList.add(new Person("Bodo Bambino", addressPerson9));
        personList.add(new Person("Ortrun Giner", addressPerson10));
        personList.add(new Person("Jakob Huber", addressPerson11));
        return personList;
    }
}

Person.java - my Person class

package AddressBook;

import javafx.beans.property.SimpleStringProperty;

public class Person {

    private SimpleStringProperty name;
    private Address address;

    public Person() {
        this.name = new SimpleStringProperty("");
        this.address = new Address("", "", "");
    }

    public Person(String name, Address address) {
        this.name = new SimpleStringProperty(name);
        ;
        this.address = address;
    }


    public String getName() {
        return name.get();
    }

    public void setName(String name2) {
        name.set(name2);
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }
}

In MainController.java - for certain things like closing the window or for deleting a person I call a method like this as my own confirmdialogwindow with corresponding String for the Label.

        boolean answer = confirmDialogBoxController.display("Exiting Window", "Are you sure you want to close the window?");
        if (answer) {

            MiniTest.getPrimaryStage().close();
        }

and here is the full MainController.java - this is the mainController for the mainView(View.fxml)

package AddressBook;

import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue;

import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
import javafx.util.Callback;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;

public class MainController implements Initializable {

    @FXML
    private MenuItem exitMenu;

    @FXML
    private TableView<Person> personTable;
    @FXML
    private TextField zipInput;
    @FXML
    private TextField cityInput;
    @FXML
    private TextField streetInput;
    @FXML
    private TextField nameInput;
    @FXML
    private TableColumn<Person, String> cityColumn;
    @FXML
    private TableColumn<Person, String> zipColumn;
    @FXML
    private TableColumn<Person, String> streetColumn;
    @FXML
    private TableColumn<Person, String> nameColumn;
    @FXML
    private Button addButton;
    @FXML
    private Button deleteButton;
    @FXML
    private SimpleStringProperty message;

    private Stage window;
    private ConfirmDialogBoxController confirmDialogBoxController;
    private AlertEmptyNameController alertEmptyNameController;
    private Model model;

    public MainController(){
        model = new Model();
        System.out.println("+1 MainController()");
    }
    public MainController(Model model){

        this.model = model;
        System.out.println("+1 MainController(model)");
    }



    @Override
    public void initialize(URL location, ResourceBundle resources) {

        Callback<TableColumn<Person, String>, TableCell<Person, String>> cellFactory = (TableColumn<Person, String> p) -> new MainController.EditingCell();

        nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
        nameColumn.setCellFactory(cellFactory);
        nameColumn.setOnEditCommit(
                (
                        TableColumn.CellEditEvent<Person, String> t) ->

                {
                    ((Person) t.getTableView().getItems().get(t.getTablePosition().getRow())).setName(t.getNewValue());
                }
        );

        streetColumn.setCellValueFactory(person -> new

                SimpleStringProperty(person.getValue().

                getAddress().

                getStreet()));
        streetColumn.setCellFactory(cellFactory);
        streetColumn.setOnEditCommit(
                (
                        TableColumn.CellEditEvent<Person, String> t) ->

                {
                    ((Person) t.getTableView().getItems().get(t.getTablePosition().getRow())).getAddress().setStreet(t.getNewValue());
                });

        zipColumn.setCellValueFactory(person -> new

                SimpleStringProperty(person.getValue().

                getAddress().

                getZip()));
        zipColumn.setCellFactory(cellFactory);
        zipColumn.setOnEditCommit(
                (
                        TableColumn.CellEditEvent<Person, String> t) ->

                {
                    ((Person) t.getTableView().getItems().get(t.getTablePosition().getRow())).getAddress().setZip(t.getNewValue());
                });

        cityColumn.setCellValueFactory(person -> new

                SimpleStringProperty(person.getValue().

                getAddress().

                getCity()));
        cityColumn.setCellFactory(cellFactory);
        cityColumn.setOnEditCommit(
                (
                        TableColumn.CellEditEvent<Person, String> t) ->

                {
                    ((Person) t.getTableView().getItems().get(t.getTablePosition().getRow())).getAddress().setCity(t.getNewValue());
                });
        personTable.setItems(model.getPerson());
        personTable.setEditable(true);


        MiniTest.getPrimaryStage().setOnCloseRequest(e -> {

            try {
                e.consume();
                closeWindow(e);
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        });
    }

    public SimpleStringProperty getMessageProperty(){

        return message;
    }

    public void setMessage(String message) {

        this.message.setValue(message);
    }

    public String getMessage() {

        return this.message.getValue();
    }


    @FXML
    public void closeWindow(WindowEvent e) throws IOException {

        boolean answer = confirmDialogBoxController.display("Exiting Window", "Are you sure you want to close the window?");
        if (answer) {

            MiniTest.getPrimaryStage().close();
        }
    }

    @FXML
    public void closeWindowFromMenu(ActionEvent e) throws IOException {

        boolean answer = confirmDialogBoxController.display("Exiting Window", "Are you sure you want to close the window?");
        if (answer) {

            MiniTest.getPrimaryStage().close();
        }
    }

    public Stage getPrimaryStage() {

        return window;
    }

    @FXML
    public void addNewPerson() throws IOException {

        alertEmptyNameController = new AlertEmptyNameController();
        Person person = new Person();
        person.setName(nameInput.getText());
        if(nameInput.getText().isEmpty()){
            alertEmptyNameController.alertEmptyName();
        }else{
        person.getAddress().setStreet(streetInput.getText());
        person.getAddress().setZip(zipInput.getText());
        person.getAddress().setCity(cityInput.getText());
        personTable.getItems().add(person);
        }
        nameInput.clear();
        streetInput.clear();
        zipInput.clear();
        cityInput.clear();
    }

    @FXML
    public void deletePerson() throws IOException {

        boolean answer = confirmDialogBoxController.display("Deleting Entry", "Are you sure you want to delete this entry?");
        if (answer) {
            ObservableList<Person> personSelected, allPersons;
            allPersons = personTable.getItems();
            personSelected = personTable.getSelectionModel().getSelectedItems();
            personSelected.forEach(allPersons::remove);
        }

    }

    static class EditingCell extends TableCell<Person, String> {

        private TextField textField;

        public EditingCell() {
        }

        @Override
        public void startEdit() {

            if (!isEmpty()) {
                super.startEdit();
                createTextField();
                setText(null);
                setGraphic(textField);
                textField.selectAll();
            }
        }

        @Override
        public void cancelEdit() {

            super.cancelEdit();
            setText((String) getItem());
            setGraphic(null);
        }

        @Override
        public void updateItem(String item, boolean empty) {

            super.updateItem(item, empty);

            if (empty) {
                setText(null);
                setGraphic(null);
            } else {
                if (isEditing()) {
                    if (textField != null) {
                        textField.setText(getString());
                    }
                    setText(null);
                    setGraphic(textField);
                } else {
                    setText(getString());
                    setGraphic(null);
                }
            }
        }

        private void createTextField() {

            textField = new TextField(getString());
            textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
            textField.focusedProperty().addListener((ObservableValue<? extends Boolean> arg0,
                                                     Boolean arg1, Boolean arg2) -> {
                if (!arg2) {
                    commitEdit(textField.getText());
                }
            });
        }

        private String getString() {
            return getItem() == null ? "" : getItem();
        }
    }
}

View.fxml - this is the main View

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>


<BorderPane fx:id="borderPane" stylesheets="@MyStyle.css" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="AddressBook.MainController">
    <bottom>
        <HBox fx:id="bottomLayout" alignment="CENTER" style="-fx-background-color: #292929;" BorderPane.alignment="CENTER">
            <BorderPane.margin>
                <Insets />
            </BorderPane.margin>
            <children>
                <TextField fx:id="nameInput" promptText="Name" style="-fx-background-radius: 0;">
                    <HBox.margin>
                        <Insets bottom="8.0" left="8.0" right="5.0" top="10.0" />
                    </HBox.margin>
                </TextField>
                <TextField fx:id="streetInput" layoutX="15.0" layoutY="15.0" promptText="Street" style="-fx-background-radius: 0;">
                    <HBox.margin>
                        <Insets bottom="8.0" left="5.0" right="5.0" top="10.0" />
                    </HBox.margin>
                </TextField>
                <TextField fx:id="zipInput" layoutX="163.0" layoutY="15.0" promptText="Zip" style="-fx-background-radius: 0;">
                    <HBox.margin>
                        <Insets bottom="8.0" left="5.0" right="5.0" top="10.0" />
                    </HBox.margin>
                </TextField>
                <TextField fx:id="cityInput" layoutX="312.0" layoutY="15.0" promptText="City" style="-fx-background-radius: 0;">
                    <HBox.margin>
                        <Insets bottom="8.0" left="5.0" right="5.0" top="10.0" />
                    </HBox.margin>
                </TextField>
                <Button fx:id="addButton" mnemonicParsing="false" onAction="#addNewPerson" style="-fx-background-color: #5ebcff; -fx-background-radius: 0; -fx-text-fill: white;" text="Add">
                    <HBox.margin>
                        <Insets bottom="8.0" left="5.0" right="5.0" top="10.0" />
                    </HBox.margin>
                </Button>
                <Button fx:id="deleteButton" layoutX="474.0" layoutY="15.0" mnemonicParsing="false" onAction="#deletePerson" style="-fx-background-radius: 0; -fx-background-color: #5ebcff; -fx-text-fill: white;" text="Delete">
                    <HBox.margin>
                        <Insets bottom="8.0" left="5.0" right="8.0" top="10.0" />
                    </HBox.margin>
                </Button>
            </children>
        </HBox>
    </bottom>
    <center>
        <TableView fx:id="personTable" editable="true" style="-fx-background-color: #5e5e5e;" stylesheets="@MyStyle.css" BorderPane.alignment="CENTER">
            <columns>
                <TableColumn fx:id="nameColumn" prefWidth="152.0" text="Name" />
                <TableColumn fx:id="streetColumn" prefWidth="196.0" text="Street" />
                <TableColumn fx:id="zipColumn" prefWidth="88.0" text="Zip" />
                <TableColumn fx:id="cityColumn" prefWidth="163.0" text="City" />
            </columns>
        </TableView>
    </center>
    <top>
        <HBox fx:id="menuLayout" style="-fx-background-color: #292929;" stylesheets="@MyStyle.css" BorderPane.alignment="CENTER">
            <children>
                <MenuBar fx:id="menuBar" stylesheets="@MyStyle.css">
                    <menus>
                        <Menu fx:id="fileMenu" mnemonicParsing="false" text="File">
                            <items>
                                <MenuItem fx:id="exitMenu" mnemonicParsing="false" onAction="#closeWindowFromMenu" text="Exit" />
                            </items>
                        </Menu>
                    </menus>
                </MenuBar>
            </children>
        </HBox>
    </top>
</BorderPane>

ConfirmDialogBoxController.java - this is the controller for the confirm dialog box for closing window with the "X" or in the menu File->Exit and for asking the user if he really wants to delete the entry in the tableview

package AddressBook;

import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.stage.Modality;
import javafx.stage.Stage;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;

public class ConfirmDialogBoxController implements Initializable {

    private static Boolean answer;
    @FXML
    private Button yesButton;
    @FXML
    private Button noButton;
    @FXML
    private Label confirmLabel;
    @FXML
    private Stage stage;
    @FXML
    private Model model;

    public ConfirmDialogBoxController(){

        System.out.println("+1 ConfirmDialogBoxController() object instantiated");
        }

    public ConfirmDialogBoxController(Model model){
        this.model = model;
        System.out.println("+1 ConfirmDialogBoxController(model) object instantiated");
}

    public boolean display(String title, String message) throws IOException {

        FXMLLoader confirmViewLoader = new FXMLLoader(getClass().getResource("ConfirmDialogBoxView.fxml"));
        confirmViewLoader.load();
        ConfirmDialogBoxController confirmDialogBoxController = confirmViewLoader.getController();
        confirmDialogBoxController.confirmLabel.setText(message);
        Parent root = confirmViewLoader.getRoot();
        Stage stage = new Stage();
        stage.setTitle(title);
        stage.setScene(new Scene(root));
        stage.initModality(Modality.APPLICATION_MODAL);
        System.out.println("MessageVariable in DisplayMethod is:"+message);
        stage.showAndWait();
        return answer;
    }

    public Label getLabel(){
        return confirmLabel;
    }

    @FXML
    public boolean yesButtonClicked(ActionEvent actionEvent) {

        answer = true;
        stage = (Stage) yesButton.getScene().getWindow();
        stage.close();
        return answer;
    }

    @FXML
    public boolean noButtonClicked(ActionEvent actionEvent) {

        answer = false;
        Stage confirmWindow = (Stage) noButton.getScene().getWindow();
        confirmWindow.close();
        return answer;
    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {

//        confirmLabel.textProperty().bindBidirectional(messageProperty);
//        System.out.println("messageProperty.getValue(): "+ messageProperty.getValue());
//        System.out.println("DEBUG: message is = " + messageProperty.get());
    }
}

ConfirmDialogBoxView.fxml - this is the ConfirmDialogBox View

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<AnchorPane prefWidth="450.0" stylesheets="@MyStyle.css" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="AddressBook.ConfirmDialogBoxController">
   <children>
      <VBox fx:id="vBox" alignment="CENTER" spacing="20.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
         <children>
            <Label fx:id="confirmLabel"  textAlignment="CENTER" />
            <HBox fx:id="hBox" alignment="CENTER" spacing="10.0">
               <children>
                  <Button fx:id="yesButton" alignment="CENTER" contentDisplay="CENTER" mnemonicParsing="false" onAction="#yesButtonClicked" text="Yes" textAlignment="CENTER">
                     <HBox.margin>
                        <Insets />
                     </HBox.margin>
                  </Button>
                  <Button fx:id="noButton" alignment="CENTER" contentDisplay="CENTER" layoutX="10.0" layoutY="10.0" mnemonicParsing="false" onAction="#noButtonClicked" text="No" textAlignment="CENTER">
                     <HBox.margin>
                        <Insets />
                     </HBox.margin>
                  </Button>
               </children>
               <VBox.margin>
                  <Insets />
               </VBox.margin>
            </HBox>
         </children>
         <padding>
            <Insets bottom="50.0" top="30.0" />
         </padding>
      </VBox>
   </children>
</AnchorPane>

AlertEmptyNameController.java - this is the controller for the view when the name field is empty and you click on add person


package AddressBook;

import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.stage.Modality;
import javafx.stage.Stage;

import java.io.IOException;

public class AlertEmptyNameController {

    @FXML
        private Button okButton;
        @FXML
        private Label emptyNameLabel;
        private Stage alertEmptyNamestage;
        private Model model;
        private AlertEmptyNameController alertEmptyNameController;

    public AlertEmptyNameController() {

        System.out.println("+1 AlertEmptyNameControlle() object instantiated");
    }

        public AlertEmptyNameController(Model model){

            this.model = model;
            System.out.println("+1 AlertEmptyNameController(model) object instantiated");
        }

        public void alertEmptyName() throws IOException {

            FXMLLoader alertEmptyNameLoader = new FXMLLoader(getClass().getResource("AlertEmptyNameView.fxml"));
            alertEmptyNameLoader.load();
            AlertEmptyNameController alertEmptyNameController = alertEmptyNameLoader.getController();
            Parent root = alertEmptyNameLoader.getRoot();
            alertEmptyNamestage = new Stage();
            alertEmptyNamestage.setScene(new Scene(root));
            alertEmptyNamestage.setTitle("The Namefield is empty!");
            alertEmptyNamestage.initModality(Modality.APPLICATION_MODAL);
            alertEmptyNamestage.showAndWait();
        }

        @FXML
        public boolean okButtonClicked(ActionEvent actionEvent) {
            boolean answer = true;
            alertEmptyNamestage = (Stage) okButton.getScene().getWindow();
            alertEmptyNamestage.close();
            return answer;
        }
}

AlertEmptyNameView.fxml - the view for AlertEmptyName

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<?import javafx.geometry.Insets?>
<AnchorPane prefHeight="250.0" prefWidth="450.0" stylesheets="@MyStyle.css" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="AddressBook.AlertEmptyNameController">
    <children>
        <VBox fx:id="vBox" alignment="CENTER" spacing="20.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
            <children>
                <Label fx:id="emptyNameLabel" text="The Namefield cannot be empty!" textAlignment="CENTER" />
                <HBox fx:id="hBox" alignment="CENTER" spacing="10.0">
                    <children>
                        <Button fx:id="okButton" alignment="CENTER" contentDisplay="CENTER" mnemonicParsing="false" onAction="#okButtonClicked" text="Ok" textAlignment="CENTER">
                            <HBox.margin>
                                <Insets />
                            </HBox.margin>
                        </Button>
                    </children>
                    <VBox.margin>
                        <Insets />
                    </VBox.margin>
                </HBox>
            </children>
            <padding>
                <Insets bottom="50.0" top="30.0" />
            </padding>
        </VBox>
    </children>
</AnchorPane>

And this is for example the NullPointerException when I wanna close the window:

Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
    at AddressBook.MainController.closeWindow(MainController.java:163)
    at AddressBook.MainController.lambda$initialize$8(MainController.java:137)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
    at javafx.event.Event.fireEvent(Event.java:198)
    at com.sun.javafx.stage.WindowPeerListener.closing(WindowPeerListener.java:88)
    at com.sun.javafx.tk.quantum.GlassWindowEventHandler.run(GlassWindowEventHandler.java:122)
    at com.sun.javafx.tk.quantum.GlassWindowEventHandler.run(GlassWindowEventHandler.java:40)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.tk.quantum.GlassWindowEventHandler.lambda$handleWindowEvent$3(GlassWindowEventHandler.java:151)
    at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:410)
    at com.sun.javafx.tk.quantum.GlassWindowEventHandler.handleWindowEvent(GlassWindowEventHandler.java:149)
    at com.sun.glass.ui.Window.handleWindowEvent(Window.java:1273)
    at com.sun.glass.ui.Window.notifyClose(Window.java:1177)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$4(WinApplication.java:186)
    at java.lang.Thread.run(Thread.java:748)

I hope that someone can help me.

Cheers


I deleted now the display() method in confirmDialogBoxController.java and put it in mainController.java

...

    public boolean display(String title, String message) throws IOException {

        FXMLLoader confirmViewLoader = new FXMLLoader(getClass().getResource("ConfirmDialogBoxView.fxml"));
        confirmViewLoader.load();
        ConfirmDialogBoxController confirmDialogBoxController = confirmViewLoader.getController();
        confirmDialogBoxController.getLabel().setText(message);
        Parent root = confirmViewLoader.getRoot();
        Stage stage = new Stage();
        stage.setTitle(title);
        stage.setScene(new Scene(root));
        stage.initModality(Modality.APPLICATION_MODAL);
        System.out.println("MessageVariable in DisplayMethod is:"+message);
        stage.showAndWait();

        return answer;
    }

    @FXML
    public void closeWindow(WindowEvent e) throws IOException {


        boolean answer = display("Exiting Window", "Are you sure you want to close the window?");
        if (answer) {

            MiniTest.getPrimaryStage().close();
        }
    }
...


Solution

  • Your confirmDialogBoxController in the main controller is null: it is never initialized. The way you have set this up is problematic: the ConfirmDialogBoxController is only initialized when the corresponding FXML is loaded (common to any FXML-controller pair), but the code for loading the FXML is in the ConfirmDialogBoxController class, so you can't load the FXML until you have a controller instance.

    It's not really the responsibility of the ConfirmDialogBoxController to display the UI defined by its FXML. You should move the display() method to your MainController class:

    public class MainController implements Initializable {
    
        // Existing code omitted...
    
        // updated close method:
    
        @FXML
        public void closeWindow(WindowEvent e) throws IOException {
    
            boolean answer = display("Exiting Window", "Are you sure you want to close the window?");
            if (answer) {
    
                MiniTest.getPrimaryStage().close();
            }
        }
    
        public boolean displayConfirmDialog(String title, String message) throws IOException {
    
            FXMLLoader confirmViewLoader = new FXMLLoader(getClass().getResource("ConfirmDialogBoxView.fxml"));
            confirmViewLoader.load();
            ConfirmDialogBoxController confirmDialogBoxController = confirmViewLoader.getController();
            confirmDialogBoxController.setConfirmMessage(message);
            Parent root = confirmViewLoader.getRoot();
            Stage stage = new Stage();
            stage.setTitle(title);
            stage.setScene(new Scene(root));
            stage.initModality(Modality.APPLICATION_MODAL);
            System.out.println("MessageVariable in DisplayMethod is:"+message);
            stage.showAndWait();
    
            // Get the user response (true = Yes button clicked) from controller:
            return confirmDialogBoxController.getResponse() ;
        }
    
    }
    

    And then update the ConfirmDialogBoxController:

    public class ConfirmDialogBoxController implements Initializable {
    
        // existing code omitted...
    
        // This should not be static, and should be a primitive type:
    
        // private static Boolean answer ;
    
        private boolean answer ;
    
        // this method removed:
        /*
        public boolean display(String title, String message) throws IOException {
    
            FXMLLoader confirmViewLoader = new FXMLLoader(getClass().getResource("ConfirmDialogBoxView.fxml"));
            confirmViewLoader.load();
            ConfirmDialogBoxController confirmDialogBoxController = confirmViewLoader.getController();
            confirmDialogBoxController.confirmLabel.setText(message);
            Parent root = confirmViewLoader.getRoot();
            Stage stage = new Stage();
            stage.setTitle(title);
            stage.setScene(new Scene(root));
            stage.initModality(Modality.APPLICATION_MODAL);
            System.out.println("MessageVariable in DisplayMethod is:"+message);
            stage.showAndWait();
            return answer;
        }
        */
    
        // This added for convenience:
        public void setConfirmMessage(String message) {
            confirmLabel.setText(message);
        }
    
        // This added to return the response (answer):
    
        public boolean getResponse() {
            return answer ;
        }
    
        // Note also your event handlers should be void:
    
        @FXML
        public void yesButtonClicked(ActionEvent actionEvent) {
    
            answer = true;
            stage = (Stage) yesButton.getScene().getWindow();
            stage.close();
            // return answer;
        }
    
        @FXML
        public void noButtonClicked(ActionEvent actionEvent) {
    
            answer = false;
            Stage confirmWindow = (Stage) noButton.getScene().getWindow();
            confirmWindow.close();
            // return answer;
        }
    
    }
    

    You probably want a similar refactoring for your other dialog.