JavaFX Embedded Table FXML 给出空指针异常
JavaFX Embedded Table FXML giving Null Pointer Exception
我正在尝试通过参考 YT 的一些教程来创建 table 视图。当我做一个简单的 table 视图及其相关控制器时,它就可以工作了。
主要Class:
public class TableTest extends Application {
public TableTest() {
// TODO Auto-generated constructor stub
}
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) throws Exception {
try {
// load the fxml file
FXMLLoader tableloader = new FXMLLoader(getClass().getResource("TestTableView.fxml"));
Parent root = tableloader.load();
TableTestController controller = tableloader.getController();
controller.initializeModel();
//load the login scene
Scene scene = new Scene(root, 800, 400);
stage.setTitle("Test Table Screen");
stage.setScene(scene);
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
}
控制器Class:
public class TableTestController {
@FXML private TableView<TablePost> t_posts ;
@FXML private TableColumn<TablePost, String> c_post_id ;
@FXML private TableColumn<TablePost, String> c_post_title ;
@FXML private TableColumn<TablePost, String> c_post_desc ;
@FXML private TableColumn<TablePost, String> c_post_creator ;
@FXML private TabPane TabPane;
@FXML private Tab AllPosts;
@FXML private AnchorPane t_anch;
@FXML private TableTestController t_anchController;
@FXML private Parent TAllPosts;
public void initializeModel() {
System.out.println("Starting Table Init");
c_post_id.setCellValueFactory(new PropertyValueFactory<TablePost, String>("postId"));
c_post_title.setCellValueFactory(new PropertyValueFactory<TablePost, String>("postTitle"));
c_post_desc.setCellValueFactory(new PropertyValueFactory<TablePost, String>("postDesc"));
c_post_creator.setCellValueFactory(new PropertyValueFactory<TablePost, String>("postCreator"));
t_posts.setItems(getPosts());
System.out.println("Finished Table Init");
}
public ObservableList<TablePost> getPosts() {
ObservableList<TablePost> posts = FXCollections.observableArrayList();
TablePost p1 ;
p1 = new TablePost("id1","title1","desc1","creator1");
posts.add(p1);
p1 = new TablePost("id2","title2","desc2","creator2");
posts.add(p1);
return posts;
}
}
TestTableView.fxml :
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.cell.PropertyValueFactory?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity"
minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0"
prefWidth="600.0" xmlns="http://javafx.com/javafx/11.0.1"
xmlns:fx="http://javafx.com/fxml/1"
fx:id ="t_anch"
fx:controller="test.TableTestController">
<children>
<TableView fx:id="t_posts" layoutX="14.0" layoutY="65.0"
prefHeight="141.0" prefWidth="570.0">
<columns>
<TableColumn fx:id="c_post_id" prefWidth="78.0"
text="Post Id" />
<TableColumn fx:id="c_post_title" prefWidth="135.0"
text="Post Title" />
<TableColumn fx:id="c_post_desc" prefWidth="237.0"
text="Post Desc" />
<TableColumn fx:id="c_post_creator" prefWidth="119.0"
text="Post Creator" />
</columns>
</TableView>
</children>
</AnchorPane>
所有这些都有效,但是此刻,我将此 fxml 注入到选项卡视图中,我得到了 NPE。
也就是说,如果我在 Main class 中更改第 28 行以引用基于新选项卡的 fxml,它会失败
这个有效:FXMLLoader tableloader = new FXMLLoader(getClass().getResource("TestTableView.fxml"));
这不起作用:FXMLLoader tableloader = new FXMLLoader(getClass().getResource("TestTableView2.fxml"));
TestTableView2.fxml :
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Tab?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.layout.BorderPane?>
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity"
minHeight="-Infinity" minWidth="-Infinity" prefHeight="515.0"
prefWidth="714.0" xmlns="http://javafx.com/javafx/11.0.1"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="test.TableTestController">
<center>
<TabPane fx:id="TabPane">
<tabs>
<Tab fx:id="AllPosts" closable="false" text="All Posts">
<content>
<fx:include fx:id="TAllPosts"
source="TestTableView.fxml" />
</content>
</Tab>
</tabs>
</TabPane>
</center>
</BorderPane>
您可以简单地在 TableView2
的控制器中进行初始化。还要在控制器中添加 AllPosts
而不是 fxml:
public class TableView2Controller {
@FXML private Tab AllPosts;
@FXML
public void initialize() throws IOException {
FXMLLoader loader = new FXMLLoader(getClass().getResource("TestTableView.fxml"));
Pane pane = loader.load();
TableTestController controller = loader.getController();
controller.initializeModel();
AllPosts.setContent(pane);
}
}
多亏了 Slaw、Fabian 和 James_D 的建议,再加上几个小时的网上教程,我现在已经解决了这个问题。
- 我不得不使用嵌套控制器。
- 子 fxml 的名称应与主 fxml 中定义为 fx:id 的名称相匹配。这
如果我们以与子 fxml 名称相同的格式指定它,但在末尾添加 Controller 并将首字母小写,则子 fxml 的控制器将自动注入。请参阅下面我更新的工作代码。
我的TestTableView.fxml是-
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.cell.PropertyValueFactory?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity"
minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0"
prefWidth="600.0" xmlns="http://javafx.com/javafx/11.0.1"
xmlns:fx="http://javafx.com/fxml/1"
fx:id ="t_anch"
fx:controller="test.TestTableViewController">
<children>
<TableView fx:id="t_posts" layoutX="14.0" layoutY="65.0"
prefHeight="141.0" prefWidth="570.0">
<columns>
<TableColumn fx:id="c_post_id" prefWidth="78.0"
text="Post Id" />
<TableColumn fx:id="c_post_title" prefWidth="135.0"
text="Post Title" />
<TableColumn fx:id="c_post_desc" prefWidth="237.0"
text="Post Desc" />
<TableColumn fx:id="c_post_creator" prefWidth="119.0"
text="Post Creator" />
</columns>
</TableView>
</children>
</AnchorPane>
我的TestTableView2.fxml是-
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Tab?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.layout.BorderPane?>
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity"
minHeight="-Infinity" minWidth="-Infinity" prefHeight="515.0"
prefWidth="714.0" xmlns="http://javafx.com/javafx/11.0.1"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="test.TestTableView2Controller">
<center>
<TabPane>
<tabs>
<Tab closable="false" text="All Posts">
<content>
<fx:include fx:id="testTableView"
source="TestTableView.fxml" />
</content>
</Tab>
</tabs>
</TabPane>
</center>
</BorderPane>
测试表视图控制器
package test;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.Parent;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.AnchorPane;
import model.app.posts.TablePost;
public class TestTableViewController {
@FXML private TableView<TablePost> t_posts ;
@FXML private TableColumn<TablePost, String> c_post_id ;
@FXML private TableColumn<TablePost, String> c_post_title ;
@FXML private TableColumn<TablePost, String> c_post_desc ;
@FXML private TableColumn<TablePost, String> c_post_creator ;
@FXML private TabPane TabPane;
@FXML private Tab AllPosts;
@FXML private AnchorPane t_anch;
@FXML private TestTableViewController t_anchController;
@FXML private Parent TAllPosts;
@FXML
public void initialize() {
System.out.println("Starting Table Init");
c_post_id.setCellValueFactory(new PropertyValueFactory<TablePost, String>("postId"));
c_post_title.setCellValueFactory(new PropertyValueFactory<TablePost, String>("postTitle"));
c_post_desc.setCellValueFactory(new PropertyValueFactory<TablePost, String>("postDesc"));
c_post_creator.setCellValueFactory(new PropertyValueFactory<TablePost, String>("postCreator"));
System.out.println("Finished Table Init");
}
public void setTableItems(ObservableList<TablePost> posts) {
t_posts.setItems(posts);
}
}
TestTableView2Controller
package test;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import model.app.posts.TablePost;
public class TestTableView2Controller {
@FXML private TestTableViewController testTableViewController;
@FXML private void initialize() {
ObservableList<TablePost> posts = FXCollections.observableArrayList();
TablePost p1 ;
p1 = new TablePost("id5","title1","desc1","creator1","OPEN");
posts.add(p1);
p1 = new TablePost("id6","title2","desc2","creator2","CLOSED");
posts.add(p1);
testTableViewController.setTableItems(posts);
}
}
最后 TableTest.java
package test;
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class TableTest extends Application {
public TableTest() {
// TODO Auto-generated constructor stub
}
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) throws Exception {
try {
// load the fxml file
FXMLLoader tableloader = new FXMLLoader(getClass().getResource("TestTableView2.fxml"));
Parent root = tableloader.load();
//load the login scene
Scene scene = new Scene(root, 800, 400);
stage.setTitle("Test Table Screen");
stage.setScene(scene);
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
}
我正在尝试通过参考 YT 的一些教程来创建 table 视图。当我做一个简单的 table 视图及其相关控制器时,它就可以工作了。
主要Class:
public class TableTest extends Application {
public TableTest() {
// TODO Auto-generated constructor stub
}
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) throws Exception {
try {
// load the fxml file
FXMLLoader tableloader = new FXMLLoader(getClass().getResource("TestTableView.fxml"));
Parent root = tableloader.load();
TableTestController controller = tableloader.getController();
controller.initializeModel();
//load the login scene
Scene scene = new Scene(root, 800, 400);
stage.setTitle("Test Table Screen");
stage.setScene(scene);
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
}
控制器Class:
public class TableTestController {
@FXML private TableView<TablePost> t_posts ;
@FXML private TableColumn<TablePost, String> c_post_id ;
@FXML private TableColumn<TablePost, String> c_post_title ;
@FXML private TableColumn<TablePost, String> c_post_desc ;
@FXML private TableColumn<TablePost, String> c_post_creator ;
@FXML private TabPane TabPane;
@FXML private Tab AllPosts;
@FXML private AnchorPane t_anch;
@FXML private TableTestController t_anchController;
@FXML private Parent TAllPosts;
public void initializeModel() {
System.out.println("Starting Table Init");
c_post_id.setCellValueFactory(new PropertyValueFactory<TablePost, String>("postId"));
c_post_title.setCellValueFactory(new PropertyValueFactory<TablePost, String>("postTitle"));
c_post_desc.setCellValueFactory(new PropertyValueFactory<TablePost, String>("postDesc"));
c_post_creator.setCellValueFactory(new PropertyValueFactory<TablePost, String>("postCreator"));
t_posts.setItems(getPosts());
System.out.println("Finished Table Init");
}
public ObservableList<TablePost> getPosts() {
ObservableList<TablePost> posts = FXCollections.observableArrayList();
TablePost p1 ;
p1 = new TablePost("id1","title1","desc1","creator1");
posts.add(p1);
p1 = new TablePost("id2","title2","desc2","creator2");
posts.add(p1);
return posts;
}
}
TestTableView.fxml :
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.cell.PropertyValueFactory?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity"
minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0"
prefWidth="600.0" xmlns="http://javafx.com/javafx/11.0.1"
xmlns:fx="http://javafx.com/fxml/1"
fx:id ="t_anch"
fx:controller="test.TableTestController">
<children>
<TableView fx:id="t_posts" layoutX="14.0" layoutY="65.0"
prefHeight="141.0" prefWidth="570.0">
<columns>
<TableColumn fx:id="c_post_id" prefWidth="78.0"
text="Post Id" />
<TableColumn fx:id="c_post_title" prefWidth="135.0"
text="Post Title" />
<TableColumn fx:id="c_post_desc" prefWidth="237.0"
text="Post Desc" />
<TableColumn fx:id="c_post_creator" prefWidth="119.0"
text="Post Creator" />
</columns>
</TableView>
</children>
</AnchorPane>
所有这些都有效,但是此刻,我将此 fxml 注入到选项卡视图中,我得到了 NPE。 也就是说,如果我在 Main class 中更改第 28 行以引用基于新选项卡的 fxml,它会失败
这个有效:FXMLLoader tableloader = new FXMLLoader(getClass().getResource("TestTableView.fxml"));
这不起作用:FXMLLoader tableloader = new FXMLLoader(getClass().getResource("TestTableView2.fxml"));
TestTableView2.fxml :
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Tab?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.layout.BorderPane?>
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity"
minHeight="-Infinity" minWidth="-Infinity" prefHeight="515.0"
prefWidth="714.0" xmlns="http://javafx.com/javafx/11.0.1"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="test.TableTestController">
<center>
<TabPane fx:id="TabPane">
<tabs>
<Tab fx:id="AllPosts" closable="false" text="All Posts">
<content>
<fx:include fx:id="TAllPosts"
source="TestTableView.fxml" />
</content>
</Tab>
</tabs>
</TabPane>
</center>
</BorderPane>
您可以简单地在 TableView2
的控制器中进行初始化。还要在控制器中添加 AllPosts
而不是 fxml:
public class TableView2Controller {
@FXML private Tab AllPosts;
@FXML
public void initialize() throws IOException {
FXMLLoader loader = new FXMLLoader(getClass().getResource("TestTableView.fxml"));
Pane pane = loader.load();
TableTestController controller = loader.getController();
controller.initializeModel();
AllPosts.setContent(pane);
}
}
多亏了 Slaw、Fabian 和 James_D 的建议,再加上几个小时的网上教程,我现在已经解决了这个问题。
- 我不得不使用嵌套控制器。
- 子 fxml 的名称应与主 fxml 中定义为 fx:id 的名称相匹配。这 如果我们以与子 fxml 名称相同的格式指定它,但在末尾添加 Controller 并将首字母小写,则子 fxml 的控制器将自动注入。请参阅下面我更新的工作代码。
我的TestTableView.fxml是-
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.cell.PropertyValueFactory?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity"
minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0"
prefWidth="600.0" xmlns="http://javafx.com/javafx/11.0.1"
xmlns:fx="http://javafx.com/fxml/1"
fx:id ="t_anch"
fx:controller="test.TestTableViewController">
<children>
<TableView fx:id="t_posts" layoutX="14.0" layoutY="65.0"
prefHeight="141.0" prefWidth="570.0">
<columns>
<TableColumn fx:id="c_post_id" prefWidth="78.0"
text="Post Id" />
<TableColumn fx:id="c_post_title" prefWidth="135.0"
text="Post Title" />
<TableColumn fx:id="c_post_desc" prefWidth="237.0"
text="Post Desc" />
<TableColumn fx:id="c_post_creator" prefWidth="119.0"
text="Post Creator" />
</columns>
</TableView>
</children>
</AnchorPane>
我的TestTableView2.fxml是-
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Tab?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.layout.BorderPane?>
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity"
minHeight="-Infinity" minWidth="-Infinity" prefHeight="515.0"
prefWidth="714.0" xmlns="http://javafx.com/javafx/11.0.1"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="test.TestTableView2Controller">
<center>
<TabPane>
<tabs>
<Tab closable="false" text="All Posts">
<content>
<fx:include fx:id="testTableView"
source="TestTableView.fxml" />
</content>
</Tab>
</tabs>
</TabPane>
</center>
</BorderPane>
测试表视图控制器
package test;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.Parent;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.AnchorPane;
import model.app.posts.TablePost;
public class TestTableViewController {
@FXML private TableView<TablePost> t_posts ;
@FXML private TableColumn<TablePost, String> c_post_id ;
@FXML private TableColumn<TablePost, String> c_post_title ;
@FXML private TableColumn<TablePost, String> c_post_desc ;
@FXML private TableColumn<TablePost, String> c_post_creator ;
@FXML private TabPane TabPane;
@FXML private Tab AllPosts;
@FXML private AnchorPane t_anch;
@FXML private TestTableViewController t_anchController;
@FXML private Parent TAllPosts;
@FXML
public void initialize() {
System.out.println("Starting Table Init");
c_post_id.setCellValueFactory(new PropertyValueFactory<TablePost, String>("postId"));
c_post_title.setCellValueFactory(new PropertyValueFactory<TablePost, String>("postTitle"));
c_post_desc.setCellValueFactory(new PropertyValueFactory<TablePost, String>("postDesc"));
c_post_creator.setCellValueFactory(new PropertyValueFactory<TablePost, String>("postCreator"));
System.out.println("Finished Table Init");
}
public void setTableItems(ObservableList<TablePost> posts) {
t_posts.setItems(posts);
}
}
TestTableView2Controller
package test;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import model.app.posts.TablePost;
public class TestTableView2Controller {
@FXML private TestTableViewController testTableViewController;
@FXML private void initialize() {
ObservableList<TablePost> posts = FXCollections.observableArrayList();
TablePost p1 ;
p1 = new TablePost("id5","title1","desc1","creator1","OPEN");
posts.add(p1);
p1 = new TablePost("id6","title2","desc2","creator2","CLOSED");
posts.add(p1);
testTableViewController.setTableItems(posts);
}
}
最后 TableTest.java
package test;
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class TableTest extends Application {
public TableTest() {
// TODO Auto-generated constructor stub
}
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) throws Exception {
try {
// load the fxml file
FXMLLoader tableloader = new FXMLLoader(getClass().getResource("TestTableView2.fxml"));
Parent root = tableloader.load();
//load the login scene
Scene scene = new Scene(root, 800, 400);
stage.setTitle("Test Table Screen");
stage.setScene(scene);
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
}