FXML 变量引用为空
FXML variable reference is null
所以我正在学习如何使用 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
声明了变量,在我的第一个打印语句之后,我在 [= 上得到了一个 运行time 空指针异常14=]
编辑:
上面的代码目前 运行s 没有错误,但只会填充我的 table 的 "productID" 部分。
首先,不确定 UI
class 扩展了什么。它看起来确实是从 Application
扩展而来的,并且是整个应用程序的起始 class。
根据我的最佳猜测,我会说您这样做有两个可能的原因:
- 您从第一个(
Application
扩展)class 复制而来。这不太可能,因为你说你有一个 NullPointerException
,除非你手动调用 start()
.
- 这个"controller"class是确实是起始class,你打算让它成为控制器class对于
FXMLDocument.fxml
。这似乎是这里可能的情况。
假设你想让Application
扩展class成为一个控制器,你需要创建一个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
的控制器。
有几点需要注意。
- 不要在 FXML 中使用
fx:controller
,或者创建 UI
的新实例(并设置它)作为替代。您必须将当前实例提供给FXMLLoader
。
- 通过
@FXML
注释的所有字段将仅在调用 FXMLLoader.load()
之后或在 initialize()
方法中注入(即非空)。如果您尝试调用 productID.setCellValueFactory(new PropertyValueFactory<Product, String>("productID"));
,您可能会得到一个 NullPointerException
,具体取决于您的代码顺序。
最后,您可以选择让另一个 class FXML 文件的控制器。事实上,大多数人会这样做,因为这是 MVC 的目的(这是 JavaFX 使用的架构)。当然,所有注入的字段和初始化也会移动到新的控制器class。还请记住,注入字段在构造函数中是 null
- 因此在新控制器 class.
的 initialize()
中初始化
所以我正在学习如何使用 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
声明了变量,在我的第一个打印语句之后,我在 [= 上得到了一个 运行time 空指针异常14=]
编辑: 上面的代码目前 运行s 没有错误,但只会填充我的 table 的 "productID" 部分。
首先,不确定 UI
class 扩展了什么。它看起来确实是从 Application
扩展而来的,并且是整个应用程序的起始 class。
根据我的最佳猜测,我会说您这样做有两个可能的原因:
- 您从第一个(
Application
扩展)class 复制而来。这不太可能,因为你说你有一个NullPointerException
,除非你手动调用start()
. - 这个"controller"class是确实是起始class,你打算让它成为控制器class对于
FXMLDocument.fxml
。这似乎是这里可能的情况。
假设你想让Application
扩展class成为一个控制器,你需要创建一个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
的控制器。
有几点需要注意。
- 不要在 FXML 中使用
fx:controller
,或者创建UI
的新实例(并设置它)作为替代。您必须将当前实例提供给FXMLLoader
。 - 通过
@FXML
注释的所有字段将仅在调用FXMLLoader.load()
之后或在initialize()
方法中注入(即非空)。如果您尝试调用productID.setCellValueFactory(new PropertyValueFactory<Product, String>("productID"));
,您可能会得到一个NullPointerException
,具体取决于您的代码顺序。
最后,您可以选择让另一个 class FXML 文件的控制器。事实上,大多数人会这样做,因为这是 MVC 的目的(这是 JavaFX 使用的架构)。当然,所有注入的字段和初始化也会移动到新的控制器class。还请记住,注入字段在构造函数中是 null
- 因此在新控制器 class.
initialize()
中初始化