JavaFX将对象从被调用的阶段传回

时间:2019-03-19 19:19:36

标签: java javafx

我有两个控制器。 ClientsViewController 正在调用 ClientAddWindowController ,因此后者创建了一个新阶段。我要做的是在新阶段创建客户端后,在放置该客户端的ClientsViewController上调用该方法。

我的问题是,除了ClientAddWindowController的构造方法之外,对ClientsViewController的引用还显示了nullpointer异常。我不明白为什么,因为我正在将调用者的引用传递给构造函数。当涉及到调用saveClient时,引用表明它是一个空指针。我在做什么错了?

错误

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 img

2 个答案:

答案 0 :(得分:0)

现在请检查两件事: 1.例如,通过添加以下内容来检查FXML文件的位置:

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

行:

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

并确保输入正确的地址。

  1. 在fxml文件“ client-add-window.fxml”中的主容器中找到属性fx:controller =“ your.controller.location.with.dirs.separated.by.dots”,并确保已正确控制该属性位置已设定。如果位置错误,您应该会看到红色。

答案 1 :(得分:0)

fxml文件中使用的Controller类由JavaFX在View加载时创建。 不要自己创建它们。因此,您必须稍微重组应用程序。我正在尝试引导您:

将阶段引用从ClientAddWindowController移动到ClientsViewController。以下是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();
    }
}

现在,ClientAddWindowController的重要部分删除了该阶段并为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();
    }
}

希望可以帮到您。