JavaFX在尝试用项目填充TextView时引发空指针异常

JavaFX在尝试用项目填充TextView时引发空指针异常,java,javafx,Java,Javafx,我正在尝试为学校创建一个简单的JavaFX项目,让用户玩游戏Nim。在我看来,这个概念很简单,因为我以前已经使用过java和JavaFX。当我试图通过传入一个可观察列表来设置TableView中的项时,会发生此错误。我确信列表中包含我应该能够添加的对象。我不知道怎么了 以下是我的全部代码: 主控制器类: package controllers; import format.FormatStringValueForTableView; import javafx.event.ActionEven

我正在尝试为学校创建一个简单的JavaFX项目,让用户玩游戏Nim。在我看来,这个概念很简单,因为我以前已经使用过java和JavaFX。当我试图通过传入一个可观察列表来设置TableView中的项时,会发生此错误。我确信列表中包含我应该能够添加的对象。我不知道怎么了

以下是我的全部代码:

主控制器类:

package controllers;

import format.FormatStringValueForTableView;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.stage.Stage;


import java.io.IOException;
import java.util.Random;

public class MainController {

    @FXML private TextField inputTextField;
    private final FormatStringValueForTableView formatter = new FormatStringValueForTableView();

    @FXML
    private void continueToGame(ActionEvent event) throws IOException {
        FXMLLoader parent = new FXMLLoader(getClass().getClassLoader().getResource("ui/nim_game.fxml"));
        Parent root = parent.load();

        NimGameController nimGameController = parent.getController();
        nimGameController.setList(formatter.formatString(inputTextField.getText()));

        Scene scene = new Scene(root);
        Stage appStage = (Stage) ((Node) event.getSource()).getScene().getWindow();
        appStage.setScene(scene);
        appStage.show();

    }
    @FXML
    private void generateRandomNumber(ActionEvent event){
        Random random = new Random();
        int generatedNumber = random.nextInt(999) + 22;
        inputTextField.setText(Integer.toString(generatedNumber));
    }
}
package controllers;

import entities.Node;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
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.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.stage.Stage;

import java.io.IOException;
import java.net.URL;
import java.util.List;
import java.util.ResourceBundle;

public class NimGameController implements Initializable {

    private ObservableList<Node> textInTextFieldToList;
    @FXML private TableView<Node> tableView;

    public void setList(ObservableList<Node> textInTextFieldToList) {
        this.textInTextFieldToList = textInTextFieldToList;
    }

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
        configureTable();
        populateTable();
    }

    @FXML
    private void showNumsForDebug(ActionEvent event) {
        textInTextFieldToList.forEach(System.out::println);
    }

    @FXML
    private void back(ActionEvent event) throws IOException {
        Parent parent = FXMLLoader.load(getClass().getClassLoader().getResource("ui/main.fxml"));
        Scene scene = new Scene(parent);
        Stage appStage = (Stage) ((javafx.scene.Node) event.getSource()).getScene().getWindow();
        appStage.setScene(scene);
        appStage.show();
    }

    private void configureTable() {
        TableColumn<Node, Integer> itemColumn = new TableColumn<>("Item");
        itemColumn.prefWidthProperty().bind(tableView.widthProperty().multiply(0.3));
        itemColumn.setCellValueFactory(new PropertyValueFactory<>("value"));
        itemColumn.setResizable(false);

        TableColumn<Node, Integer> levelColumn = new TableColumn<>("Level");
        levelColumn.prefWidthProperty().bind(tableView.widthProperty().multiply(0.3));
        levelColumn.setCellValueFactory(new PropertyValueFactory<>("level"));
        levelColumn.setResizable(false);

        TableColumn<Node, Integer> functionValColumn = new TableColumn<>("Func. Val.");
        functionValColumn.prefWidthProperty().bind(tableView.widthProperty().multiply(0.4));
        functionValColumn.setCellValueFactory(new PropertyValueFactory<>("functionValue"));
        functionValColumn.setResizable(false);

        tableView.getColumns().add(itemColumn);
        tableView.getColumns().add(levelColumn);
        tableView.getColumns().add(functionValColumn);
    }

    public void populateTable(){
        if(!textInTextFieldToList.isEmpty()){
            tableView.setItems(textInTextFieldToList);
        } else {
            System.out.println("List is empty");
        }
    }
}
NimGameController类:

package controllers;

import format.FormatStringValueForTableView;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.stage.Stage;


import java.io.IOException;
import java.util.Random;

public class MainController {

    @FXML private TextField inputTextField;
    private final FormatStringValueForTableView formatter = new FormatStringValueForTableView();

    @FXML
    private void continueToGame(ActionEvent event) throws IOException {
        FXMLLoader parent = new FXMLLoader(getClass().getClassLoader().getResource("ui/nim_game.fxml"));
        Parent root = parent.load();

        NimGameController nimGameController = parent.getController();
        nimGameController.setList(formatter.formatString(inputTextField.getText()));

        Scene scene = new Scene(root);
        Stage appStage = (Stage) ((Node) event.getSource()).getScene().getWindow();
        appStage.setScene(scene);
        appStage.show();

    }
    @FXML
    private void generateRandomNumber(ActionEvent event){
        Random random = new Random();
        int generatedNumber = random.nextInt(999) + 22;
        inputTextField.setText(Integer.toString(generatedNumber));
    }
}
package controllers;

import entities.Node;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
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.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.stage.Stage;

import java.io.IOException;
import java.net.URL;
import java.util.List;
import java.util.ResourceBundle;

public class NimGameController implements Initializable {

    private ObservableList<Node> textInTextFieldToList;
    @FXML private TableView<Node> tableView;

    public void setList(ObservableList<Node> textInTextFieldToList) {
        this.textInTextFieldToList = textInTextFieldToList;
    }

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
        configureTable();
        populateTable();
    }

    @FXML
    private void showNumsForDebug(ActionEvent event) {
        textInTextFieldToList.forEach(System.out::println);
    }

    @FXML
    private void back(ActionEvent event) throws IOException {
        Parent parent = FXMLLoader.load(getClass().getClassLoader().getResource("ui/main.fxml"));
        Scene scene = new Scene(parent);
        Stage appStage = (Stage) ((javafx.scene.Node) event.getSource()).getScene().getWindow();
        appStage.setScene(scene);
        appStage.show();
    }

    private void configureTable() {
        TableColumn<Node, Integer> itemColumn = new TableColumn<>("Item");
        itemColumn.prefWidthProperty().bind(tableView.widthProperty().multiply(0.3));
        itemColumn.setCellValueFactory(new PropertyValueFactory<>("value"));
        itemColumn.setResizable(false);

        TableColumn<Node, Integer> levelColumn = new TableColumn<>("Level");
        levelColumn.prefWidthProperty().bind(tableView.widthProperty().multiply(0.3));
        levelColumn.setCellValueFactory(new PropertyValueFactory<>("level"));
        levelColumn.setResizable(false);

        TableColumn<Node, Integer> functionValColumn = new TableColumn<>("Func. Val.");
        functionValColumn.prefWidthProperty().bind(tableView.widthProperty().multiply(0.4));
        functionValColumn.setCellValueFactory(new PropertyValueFactory<>("functionValue"));
        functionValColumn.setResizable(false);

        tableView.getColumns().add(itemColumn);
        tableView.getColumns().add(levelColumn);
        tableView.getColumns().add(functionValColumn);
    }

    public void populateTable(){
        if(!textInTextFieldToList.isEmpty()){
            tableView.setItems(textInTextFieldToList);
        } else {
            System.out.println("List is empty");
        }
    }
}
main.fxml文件:

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

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

<GridPane alignment="center" hgap="10" maxHeight="300.0" maxWidth="500.0" minHeight="-Infinity" minWidth="-Infinity" prefHeight="200.0" prefWidth="431.0" vgap="10" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controllers.MainController">
   <children>
      <AnchorPane maxHeight="300.0" maxWidth="500.0" minHeight="-Infinity" minWidth="-Infinity" prefHeight="200.0" prefWidth="400.0">
         <children>
            <SplitPane dividerPositions="0.17676767676767677" orientation="VERTICAL" prefHeight="200.0" prefWidth="400.0">
              <items>
                <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="100.0" prefWidth="160.0">
                     <children>
                        <Label alignment="CENTER" layoutX="80.0" layoutY="-2.0" prefHeight="40.0" prefWidth="238.0" text="Welcome to NIM game." underline="true">
                           <font>
                              <Font name="System Bold" size="18.0" />
                           </font>
                        </Label>
                     </children>
                  </AnchorPane>
                <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="341.0">
                     <children>
                        <Label layoutX="49.0" layoutY="14.0" prefHeight="30.0" prefWidth="300.0" text="Enter a string of numbers that will be split: ">
                           <font>
                              <Font size="15.0" />
                           </font></Label>
                        <TextField fx:id="inputTextField" layoutX="49.0" layoutY="54.0" prefHeight="25.0" prefWidth="300.0" />
                        <Button layoutX="47.0" layoutY="104.0" mnemonicParsing="false" onAction="#continueToGame" prefHeight="32.0" prefWidth="102.0" text="Continue" />
                        <Button layoutX="247.0" layoutY="104.0" mnemonicParsing="false" onAction="#generateRandomNumber" prefHeight="32.0" prefWidth="102.0" text="Random" />
                     </children></AnchorPane>
              </items>
            </SplitPane>
         </children>
      </AnchorPane>
   </children>
   <columnConstraints>
      <ColumnConstraints />
   </columnConstraints>
   <rowConstraints>
      <RowConstraints />
   </rowConstraints>
</GridPane>
<?xml version="1.0" encoding="UTF-8"?>

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

<AnchorPane prefHeight="400" prefWidth="900" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controllers.NimGameController">
   <children>
      <TableView fx:id="tableView" layoutX="681.0" layoutY="14.0" prefHeight="282.0" prefWidth="205.0">
         <columns>

         </columns>
      </TableView>
      <Button layoutX="787.0" layoutY="353.0" mnemonicParsing="false" onAction="#back" prefHeight="32.0" prefWidth="99.0" text="Back" />
      <Button layoutX="787.0" layoutY="305.0" mnemonicParsing="false" onAction="#showNumsForDebug" prefHeight="32.0" prefWidth="99.0" text="Show" />
   </children>
</AnchorPane>
initialize()
,因此在调用
fxmloader.load()
期间调用
populateTable()
,这必然发生在调用
setList(…)
之前

因此,当调用
populateTable()
时,
textinextfieldtolist
仍然为null,并且
textinextfieldtolist.isEmpty()
抛出一个
NullPointerException

只需将调用移动到
populateTable
setList()
。这是有意义的,因为在设置列表之前,您无法填充表,如果您下次调用
setList()
,您可能需要重新填充表

public void setList(ObservableList<Node> textInTextFieldToList) {
    this.textInTextFieldToList = textInTextFieldToList;
    populateTable();
}

@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
    configureTable();
}
public void集合列表(observeList textInTextFieldToList){
this.textInTextFieldToList=textInTextFieldToList;
populateTable();
}
@凌驾
公共void初始化(URL、ResourceBundle、ResourceBundle){
configureTable();
}

这是否回答了您的问题?请看一下如何创建
public void setList(ObservableList<Node> textInTextFieldToList) {
    this.textInTextFieldToList = textInTextFieldToList;
    populateTable();
}

@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
    configureTable();
}