FXML变量引用为null

时间:2018-07-16 23:32:23

标签: java javafx nullpointerexception fxml fxmlloader

所以我正在学习如何使用FXMl,并且在运行时通过fx:id获取对对象的引用遇到了另一个问题,使用以下代码会得到空指针异常。

  <TableView fx:id="productTable" layoutX="92.0" layoutY="319.0" prefHeight="97.0" prefWidth="363.0" GridPane.columnIndex="7" GridPane.columnSpan="5" GridPane.rowIndex="3" GridPane.rowSpan="2">
     <columns>
        <TableColumn prefWidth="98.0" text="Product ID" fx:id="productID"/>
        <TableColumn prefWidth="110.0" text="Product Name" fx:id="productName"/>
        <TableColumn prefWidth="131.0" text="Inventory Level" fx:id="productInventoryLevel"/>
        <TableColumn prefWidth="128.0" text="Price per Unit" fx:id="productPrice"/>
     </columns>
  </TableView>
//Controller.java
@FXML private TableView<Product> productTable;
@FXML private TableColumn<Product, String> productID;
@FXML private TableColumn<Product, String>  productPrice;
@FXML private TableColumn<Product, String>  productName;
@FXML private TableColumn<Product, String>  productInventoryLevel;

//Product properties declared the same as https://docs.oracle.com/javafx/2/ui_controls/table-view.htm#
private ObservableList<Product> productData = FXCollections.observableArrayList(
        new Product(0, "Wheel", 100.99, 4, 0, 1), 
        new Product(1, "Seat", 50.0, 4, 0, 1));

@Override
public void initialize(URL url, ResourceBundle rb) {
    // TODO
    System.out.println("Product ID factories");

    productID.setCellValueFactory(new PropertyValueFactory<Product, String>("productID"));
    productPrice.setCellValueFactory(new PropertyValueFactory<Product, String>("productPrice"));
    productInventoryLevel.setCellValueFactory(new PropertyValueFactory<Product, String>("productInventoryLevel"));
    productName.setCellValueFactory(new PropertyValueFactory<Product, String>("productName"));
     productTable.setItems(productData);

      System.out.println("Set items");

}    

您可以看到我声明了@FXML标签,然后声明了变量fx:id,并且在我的第一个打印语句之后,我在productID上获得了运行时nullpointer异常

编辑: 上面的代码当前可以正常运行,但只会填充表的“ productID”部分。

1 个答案:

答案 0 :(得分:0)

首先,不确定UI类的扩展范围。它确实看起来像是从Application扩展而来的,并且是整个应用程序的起始类。

尽我最大的猜测,我会说您这样做有两个可能的原因:

  1. 您是从第一个(Application扩展)类复制的。这是不可能的,因为您说过自己有一个NullPointerException,除非您手动调用了start()
  2. 该“控制器”类确实是的起始类,您打算将其作为FXMLDocument.fxml的控制器类。这似乎是可能的情况。

假设您希望将Application扩展类用作控制器,则需要创建FXMLLoader的实例,而不是使用静态方法FXMLLoader.load()

FXMLLoader loader = new FXMLLoader(getClass().getResource("FXMLDocument.fxml"));
loader.setController(this); // You need to set this instance as the controller.
Parent root = loader.load();
// Other stuff you need to do
productID.setCellValueFactory(new PropertyValueFactory<Product, String>("productID"));

这会将UI当前正在运行的实例设置为FXMLDocument.fxml的控制器。

有几点需要注意。

  1. 请勿在FXML中使用fx:controller,也不要创建UI的新实例(并进行设置)。您必须将当前实例提供给FXMLLoader
  2. 所有通过@FXML注释的字段仅在调用FXMLLoader.load()后或以initialize()方法被注入(即非空)。如果您尝试致电productID.setCellValueFactory(new PropertyValueFactory<Product, String>("productID"));,则可能会收到NullPointerException,具体取决于代码的顺序。

最后,您确实可以选择使另一个类成为FXML文件的控制器。实际上,大多数人会这样做,因为那是MVC(JavaFX使用的体系结构)的目的。当然,所有注入的字段和初始化也将移至新的控制器类。还请记住,注入的字段是构造函数中的null-因此请在新控制器类的initialize()中进行初始化。