简体   繁体   English

FXML变量引用为null

[英]FXML variable reference is null

So I'm learning how to use FXMl and I have run into yet another problem with getting a reference to an object by fx:id at runtime, I get a null pointer exception with the following code. 因此,我正在学习如何使用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");

}    

As you can see I declare the @FXML tag, then the variable by fx:id and right after my first print statement I get a runtime nullpointer exception on the productID 如您所见,我声明了@FXML标记,然后声明了fx:id变量,并在第一个打印语句之后立即在productID上获得了运行时nullpointer异常

EDIT: The above code currently runs without error but will only populate the "productID" section of my table. 编辑:上面的代码当前运行没有错误,但只会填充我的表的“ productID”部分。

Firstly, it's not sure what the UI class extends. 首先,不确定UI类的扩展范围。 It does look like it extended from Application , and is the starting class of the whole application. 它看起来确实是从Application扩展而来的,并且是整个应用程序的起始类。

Making my best guess, I would say there are two possible reasons why you did this: 尽我最大的猜测,我会说您这样做有两个可能的原因:

  1. You copied from the first ( Application extending) class. 您是从第一个( Application扩展)类复制的。 This is unlikely since you said you had a NullPointerException , unless you manually called start() . 除非您手动调用了start() ,否则这不太可能,因为您说过您有NullPointerException
  2. This "controller" class is indeed the starting class, and you intended to let it be the controller class for FXMLDocument.fxml . 这个“控制器”类确实开始类,你打算让它成为控制器类FXMLDocument.fxml This seems to be the likely case here. 这似乎是可能的情况。

Assuming that you want the Application extending class to be a controller, you need to create an instance of FXMLLoader , instead of using the static method FXMLLoader.load() . 假设您希望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"));

This will set the currently running instance of UI as the controller for FXMLDocument.fxml . 这会将当前运行的UI实例设置为FXMLDocument.fxml的控制器。

There are several points to take note. 有几点需要注意。

  1. Do not use fx:controller in FXML, or create a new instance of UI (and setting it) as an alternative. 不要在FXML中使用fx:controller ,也不要创建新的UI实例(并将其设置)作为替代。 You must provide the current instance to the FXMLLoader . 必须将当前实例提供给FXMLLoader
  2. All fields annotated via @FXML will only be injected (ie non-null) after FXMLLoader.load() has been called, or in initialize() method. 通过@FXML注释的所有字段仅在FXMLLoader.load()之后或在initialize()方法中被注入(即非null)。 If you try to call productID.setCellValueFactory(new PropertyValueFactory<Product, String>("productID")); 如果您尝试调用productID.setCellValueFactory(new PropertyValueFactory<Product, String>("productID")); , you may get a NullPointerException , depending on the sequence of your codes. ,则可能会收到NullPointerException ,具体取决于代码的顺序。

Lastly, you do have an option of making another class the controller of the FXML file. 最后,您确实可以选择使另一个类成为FXML文件的控制器。 In fact, most people would do that as that is the purpose of MVC (which is the architecture JavaFX uses). 实际上,大多数人会这样做,因为那是MVC(JavaFX使用的体系结构)的目的。 Of course, all injected fields and initialization would also move to the new controller class. 当然,所有注入的字段和初始化也将移至新的控制器类。 Also remember that injected fields are null in constructor - so initialize in initialize() of the new controller class. 还记得那场注入是null的构造-所以初始化initialize()的新控制器类的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM