0

I have two controllers. ClientsViewController is calling ClientAddWindowController and so the latter creates new stage. What I want to do is after a client is created in new stage it calls the method on ClientsViewController where it is put.

My problem is, besides constructor of ClientAddWindowController the reference to ClientsViewController shows nullpointer exception. I can't understand why because I'm passing reference of the caller to constructor. When it comes to calling saveClient the refernce shows it's a nullpointer. What am I doing wrong?

Errors

Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
    at controllers.ClientAddWindowController.saveClient(ClientAddWindowController.java:140)
    at controllers.ClientAddWindowController.lambda$initialize$0(ClientAddWindowController.java:92)

ClientsViewController.java

public class ClientsViewController implements Initializable {

// ...

@FXML private Button addClientButton;

@FXML private ClientAddWindowController clientAddWindowController;

private Client recentlyAddedClient;

@Override
public void initialize(URL location, ResourceBundle resources) {
    addClientButton.setOnAction(event -> {
        openClientAddWindow();
    });
}

public void openClientAddWindow() {
    clientAddWindowController = new ClientAddWindowController(this);
    clientAddWindowController.showStage();
}

public void setRecentlyAddedClient(Client recentlyAddedClient) {
    this.recentlyAddedClient = recentlyAddedClient;
}}

ClientAddWindowController.java

public class  ClientAddWindowController implements Initializable {

// ...

@FXML private Button saveButton;

@FXML private Button cancelButton;

private ClientsViewController clientsViewController;

private Stage clientAddWindowStage;

public ClientAddWindowController() {}

/**
 * Upon creating controller instance, load fxml file and create new stage with scene to be shown. Chosen modality
 * does not allow to do actions other than in this stage.
 * @param clientsViewController is a calling controller
 */
public ClientAddWindowController(ClientsViewController clientsViewController) {
    this.clientsViewController = clientsViewController;
    this.clientAddWindowStage = new Stage();

    FXMLLoader loader = new FXMLLoader(getClass().getResource("/views/client-add-window.fxml"));

    try {
        clientAddWindowStage.setTitle("Dodawanie nowego klienta");
        clientAddWindowStage.initModality(Modality.APPLICATION_MODAL);
        clientAddWindowStage.setScene(new Scene(loader.load()));
    } catch (IOException e) {
        e.printStackTrace();
    }
}

@Override
public void initialize(URL location, ResourceBundle resources) {
    countryChoiceBox.getItems().addAll(new CountryList().getCountryNames());
    saveButton.setOnAction(event -> saveClient());

}

/**
 * Creates new client with informations based on given fields. After that passes this client to parent controller
 * and closes the Stage.
 */

@FXML
public void saveClient() {

    Client newClient = new Client(
            "test",
            "test",
            "test"
            );
    clientsViewController.setRecentlyAddedClient(newClient);
    clientAddWindowStage.close();
}

/**
 * Show stage provided by creating this controller.
 */
public void showStage() {
    clientAddWindowStage.show();
}}

client-add-window.fxml

    <GridPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="800.0" prefWidth="1280.0" xmlns="http://javafx.com/javafx/8.0.172-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controllers.ClientAddWindowController">
    <children>
      <TextField fx:id="nameField" GridPane.columnIndex="1" />
      <TextField fx:id="shortNameField" layoutX="330.0" layoutY="34.0" GridPane.columnIndex="1" GridPane.rowIndex="1" />
      <TextField fx:id="emailField" GridPane.columnIndex="1" GridPane.rowIndex="2" />
      <TextField fx:id="telephone1Field" GridPane.columnIndex="1" GridPane.rowIndex="3" />
      <TextField fx:id="telephone2Field" GridPane.columnIndex="1" GridPane.rowIndex="4" />
      <TextField fx:id="telephone3Field" GridPane.columnIndex="1" GridPane.rowIndex="5" />
      <Label alignment="CENTER" contentDisplay="CENTER" prefHeight="17.0" prefWidth="382.0" text="nazwa" GridPane.halignment="CENTER" />
      <Label alignment="CENTER" contentDisplay="CENTER" prefHeight="17.0" prefWidth="382.0" text="nazwa skrócona" GridPane.rowIndex="1" />
      <Label alignment="CENTER" contentDisplay="CENTER" prefHeight="17.0" prefWidth="382.0" text="e-mail" GridPane.rowIndex="2" />
      <Label alignment="CENTER" contentDisplay="CENTER" prefHeight="17.0" prefWidth="382.0" text="telefon" GridPane.rowIndex="3" />
      <Label alignment="CENTER" contentDisplay="CENTER" prefHeight="17.0" prefWidth="382.0" text="telefon 2" GridPane.rowIndex="4" />
      <Label alignment="CENTER" contentDisplay="CENTER" prefHeight="17.0" prefWidth="382.0" text="telefon 3" GridPane.rowIndex="5" />
      <Label alignment="CENTER" contentDisplay="CENTER" prefHeight="17.0" prefWidth="382.0" text="NIP" GridPane.columnIndex="2" />
      <Label alignment="CENTER" contentDisplay="CENTER" prefHeight="17.0" prefWidth="382.0" text="REGON" GridPane.columnIndex="2" GridPane.rowIndex="1" />
      <Label alignment="CENTER" contentDisplay="CENTER" prefHeight="17.0" prefWidth="382.0" text="PESEL" GridPane.columnIndex="2" GridPane.rowIndex="2" />
      <Label alignment="CENTER" contentDisplay="CENTER" prefHeight="17.0" prefWidth="382.0" text="miasto" GridPane.rowIndex="7" />
      <TextField fx:id="nipField" GridPane.columnIndex="3" />
      <TextField fx:id="regonField" GridPane.columnIndex="3" GridPane.rowIndex="1" />
      <TextField fx:id="peselField" GridPane.columnIndex="3" GridPane.rowIndex="2" />
      <Label alignment="CENTER" contentDisplay="CENTER" prefHeight="17.0" prefWidth="382.0" text="ulica" GridPane.rowIndex="8" />
      <Label alignment="CENTER" contentDisplay="CENTER" prefHeight="17.0" prefWidth="382.0" text="kod pocztowy" GridPane.rowIndex="9" />
      <Label alignment="CENTER" contentDisplay="CENTER" prefHeight="17.0" prefWidth="382.0" text="województwo" GridPane.rowIndex="10" />
      <Label alignment="CENTER" contentDisplay="CENTER" prefHeight="17.0" prefWidth="382.0" text="status klienta" GridPane.columnIndex="2" GridPane.rowIndex="4" />
      <ChoiceBox fx:id="clientStatusChoiceBox" prefHeight="25.0" prefWidth="283.0" GridPane.columnIndex="3" GridPane.rowIndex="4" />
      <TextField fx:id="cityField" GridPane.columnIndex="1" GridPane.rowIndex="7" />
      <TextField fx:id="streetField" GridPane.columnIndex="1" GridPane.rowIndex="8" />
      <TextField fx:id="postalCodeField" GridPane.columnIndex="1" GridPane.rowIndex="9" />
      <ChoiceBox fx:id="voivodeshipChoiceBox" prefHeight="25.0" prefWidth="283.0" GridPane.columnIndex="1" GridPane.rowIndex="10" />
      <Label alignment="CENTER" contentDisplay="CENTER" prefHeight="17.0" prefWidth="382.0" text="strona www" GridPane.rowIndex="6" />
      <TextField fx:id="urlField" GridPane.columnIndex="1" GridPane.rowIndex="6" />
      <Button fx:id="downloadDataButton" alignment="CENTER" contentDisplay="CENTER" mnemonicParsing="false" prefHeight="25.0" prefWidth="103.0" text="Pobierz dane" GridPane.columnIndex="4" GridPane.halignment="CENTER" />
      <Button fx:id="saveButton" alignment="CENTER" contentDisplay="CENTER" mnemonicParsing="false" onAction="#saveClient" prefHeight="25.0" prefWidth="114.0" text="Zapisz" GridPane.columnIndex="3" GridPane.halignment="CENTER" GridPane.rowIndex="15" />
      <Button fx:id="cancelButton" alignment="CENTER" contentDisplay="CENTER" mnemonicParsing="false" prefHeight="25.0" prefWidth="114.0" text="Anuluj" GridPane.columnIndex="4" GridPane.halignment="CENTER" GridPane.rowIndex="15" />
      <Label alignment="CENTER" contentDisplay="CENTER" prefHeight="17.0" prefWidth="382.0" text="kraj" GridPane.rowIndex="11" />
       <ChoiceBox fx:id="countryChoiceBox" prefHeight="25.0" prefWidth="283.0" GridPane.columnIndex="1" GridPane.rowIndex="11" />
   </children>
</GridPane>

clients-view.fxml

    <SplitPane dividerPositions="0.7978789769182782" xmlns="http://javafx.com/javafx/8.0.172-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controllers.ClientsViewController">
    <items>
        <ScrollPane fitToWidth="true" minViewportWidth="480.0" prefHeight="1026.0" prefWidth="790.0">
            <content>
                <TableView fx:id="productsView" minWidth="-Infinity" prefHeight="1007.0" prefWidth="577.0" tableMenuButtonVisible="true">
                    <columns>
                        <TableColumn fx:id="shortNameColumn" editable="false" prefWidth="138.99996948242188" text="skrót" />
                        <TableColumn fx:id="nameColumn" editable="false" prefWidth="71.0" text="nazwa" />
                        <TableColumn fx:id="cityColumn" editable="false" prefWidth="178.0" text="miasto" />
                        <TableColumn fx:id="streetColumn" editable="false" prefWidth="119.0" text="ulica" />
                  <TableColumn fx:id="voivodeshipColumn" prefWidth="75.0" text="województwo" />
                  <TableColumn fx:id="nipColumn" editable="false" prefWidth="75.0" text="nip" />
                  <TableColumn fx:id="emailColumn" prefWidth="75.0" text="e-mail" />
                  <TableColumn fx:id="telephone1Column" editable="false" prefWidth="75.0" text="telefon" />
                  <TableColumn fx:id="statusColumn" editable="false" prefWidth="75.0" text="status" />
                  <TableColumn fx:id="peselColumn" prefWidth="75.0" text="pesel" visible="false" />
                  <TableColumn fx:id="regonColumn" prefWidth="75.0" text="regon" />
                  <TableColumn fx:id="urlColumn" prefWidth="75.0" text="strona www" visible="false" />
                  <TableColumn fx:id="telephone2Column" prefWidth="75.0" text="telefon 2" visible="false" />
                  <TableColumn fx:id="telephone3Column" prefWidth="75.0" text="telefon 3" visible="false" />
                    </columns>
               <columnResizePolicy>
                  <TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
               </columnResizePolicy>
                </TableView>
            </content>
        </ScrollPane>
        <GridPane alignment="CENTER" prefHeight="1009.0" prefWidth="807.0">
            <columnConstraints>
                <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
            </columnConstraints>
            <rowConstraints>
                <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            </rowConstraints>
         <children>
            <Button fx:id="addClientButton" alignment="CENTER" mnemonicParsing="false" text="Dodaj klienta" GridPane.halignment="CENTER" />
            <Button fx:id="testButton" mnemonicParsing="false" text="Button" GridPane.halignment="CENTER" GridPane.rowIndex="1" />
         </children>
        </GridPane>
    </items>
</SplitPane>

project structure

project structure img

fabian
  • 80,457
  • 12
  • 86
  • 114
Hawwaru
  • 5
  • 2
  • 5
  • Can you please share a [Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve) so we can reproduce your issue? – Samuel Philipp Mar 19 '19 at 20:43
  • Yes, I edited the post so it is now available. – Hawwaru Mar 19 '19 at 20:57
  • There are 2 controller instances: One created using the `ClientAddWindowController(ClientsViewController clientsViewController)` constructor and another one created by `FXMLLoader` when it loads the fxml. For a proper way of passing data, see the duplicate link. The [custom component approach](https://openjfx.io/javadoc/11/javafx.fxml/javafx/fxml/doc-files/introduction_to_fxml.html#custom_components) may be what you need in this case... – fabian Mar 19 '19 at 23:36

2 Answers2

0

For now please check two things: 1. Check location of FXML file for example by add after:

FXMLLoader loader = new FXMLLoader(getClass().getResource("/views/client-add-window.fxml"));

line:

System.out.println(loader.getLocation());

and make sure about correct address.

  1. In fxml file "client-add-window.fxml" find attribute fx:controller="your.controller.location.with.dirs.separated.by.dots" in main container and make sure you have it and properly controller location is set. If location is wrong you should see red color.
Paweł
  • 205
  • 2
  • 11
  • 1. I checked it as you suggested and the path is correct: file:/C:/Users/Hawwaru/Documents/Java/gmproject/target/classes/views/client-add-window.fxml 2.The controller location is also correct, it's the same as in the other controllers that actually work. – Hawwaru Mar 19 '19 at 20:56
  • @Samuel Philipp is right. You have to call FXML loader before show additional wndow – Paweł Mar 19 '19 at 22:42
0

The Controller classes used in the fxml files are created on View load by JavaFX. Don't create them yourself. Because of that you have to restructure your application a bit. I'm trying to lead you through this:

Move the Stage reference from ClientAddWindowController to ClientsViewController. Here are the important parts from your ClientsViewController:

public class ClientsViewController implements Initializable {
    @FXML
    private Button addClientButton;
    private Stage clientAddWindowStage;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        addClientButton.setOnAction(event -> openClientAddWindow());

        try {
            clientAddWindowStage = new Stage();
            FXMLLoader loader = new FXMLLoader(getClass().getResource("/client-add-window.fxml"));
            clientAddWindowStage.setTitle("Dodawanie nowego klienta");
            clientAddWindowStage.initModality(Modality.APPLICATION_MODAL);
            clientAddWindowStage.setScene(new Scene(loader.load()));

            // get the controller and set this so the other controller can control it
            ClientAddWindowController controller = loader.getController();
            controller.setClientsViewController(this);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void openClientAddWindow() {
        clientAddWindowStage.show();
    }

    public void closeClientAddWindow() {
        clientAddWindowStage.close();
    }
}

Here now the important parts of the ClientAddWindowController remove the stage and create a setter for the ClientsViewController:

public class ClientAddWindowController implements Initializable {
    @FXML
    private Button saveButton;

    private ClientsViewController clientsViewController;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        saveButton.setOnAction(event -> saveClient());
    }

    public void setClientsViewController(ClientsViewController clientsViewController) {
        this.clientsViewController = clientsViewController;
    }

    @FXML
    public void saveClient() {
        // ...
        clientsViewController.closeClientAddWindow();
    }
}

Hope that helps you on this.

Samuel Philipp
  • 10,631
  • 12
  • 36
  • 56