在Java FX中使用initialize()方法之前,如何让控制器访问主应用程序?
在我的控制器类中,我想在在Java FX中使用initialize()方法之前,如何让控制器访问主应用程序?,java,javafx,nullpointerexception,Java,Javafx,Nullpointerexception,在我的控制器类中,我想在initialize()方法中使用一个对象。这个对象(及其getter)是在主类中定义的。因此,当我授予控制器对主应用程序的访问权限时,已经太晚了,因为对象是在未初始化的情况下调用的。这将导致出现NullPointerException 这是调用.fxml及其控制器的方法: public void showConfigurationOverview() { try { // Load configuration overview.
initialize()方法中使用一个对象。这个对象(及其getter)是在主类中定义的。因此,当我授予控制器对主应用程序的访问权限时,已经太晚了,因为对象是在未初始化的情况下调用的。这将导致出现NullPointerException
这是调用.fxml
及其控制器的方法:
public void showConfigurationOverview() {
try {
// Load configuration overview.
FXMLLoader loader = new FXMLLoader();
loader.setLocation(MainApp.class.getResource("view/ConfigurationOverview.fxml"));
AnchorPane configurationOverview = (AnchorPane) loader.load();
// Set configuration overview into the center of root layout.
rootLayout.setCenter(configurationOverview);
// Give the controller access to the main app.
ConfigurationOverviewController controller = loader.getController();
controller.setMainApp(this);
} catch (IOException e) {
e.printStackTrace();
}
}
如果无法提前访问,我如何找到解决方案?我应该在我的控制器类中做些什么吗
编辑:
谢谢你的回答。我尝试过麦克沃尔夫先生的解决方案,效果很好。然而,控制器类中我的setMainApp
方法如下:
public void setMainApp(MainApp mainApp) {
this.mainApp = mainApp;
// Add observable list data to the table
configurationTable.setItems(mainApp.getConfigurationData());
}
但我必须将函数放置在其他位置,以便将可观察列表数据添加到表中。我做对了吗
此外,我还想尝试Slaw(和Fabian)的解决方案,但我不明白您实际上在做什么,为什么要将这个
传递给我的控制器类的构造函数。提前感谢initialize()
我假设您指的是控制器中的initialize()
方法,而不是应用程序中的init()
方法(如果我弄错了,请告诉我)。有两种方法可以做到这一点:
不要在FXML文件中使用fx:controller
。而是创建自己的实例并对其进行配置。然后在调用load()
之前调用loader.setController(controller)
使用控制器工厂通过。在这里,您仍然可以使用fx:controller
,并且实际上可以将这个
传递到控制器类的构造函数中
选项2的示例:
如果知道控制器工厂将仅实例化控制器
,则可以删除if
检查以及else
中的所有内容
编辑:选项2的备选示例
费边在评论中提到了这一点。我把它贴在这里是因为阅读答案中的代码要比阅读注释容易得多
loader.setControllerFactory(clazz -> {
Object controller;
try {
controller = clazz.getConstructor().newInstance();
} catch (ReflectiveOperationException ex) {
throw new RuntimeException(ex);
}
if (controller instanceof BaseController) {
((BaseController) controller).setMainApp(this);
}
return controller;
});
其中,BaseController
可以是某个接口或抽象类。这允许您避免检查需要特殊处理的每种类型
fabian再次提到,您可以通过引入依赖注入框架(如AfterburnerFX或CDI(上下文和依赖注入))来进一步实现这一点。要做到这一点,您可以创建控制器的手动实例,在其中注入所需的对象。然后您只需提交fxmloader
的实例
但是,要执行此操作,必须从FXML
文件中删除fx:controller
语句
public void showConfigurationOverview() {
try {
ConfigurationOverviewController controller = new ConfigurationOverviewController();
controller.setMainApp(this);
// Load configuration overview.
FXMLLoader loader = new FXMLLoader();
loader.setLocation(MainApp.class.getResource("view/ConfigurationOverview.fxml"));
loader.setController(controller);
AnchorPane configurationOverview = (AnchorPane) loader.load();
// Set configuration overview into the center of root layout.
rootLayout.setCenter(configurationOverview);
// Give the controller access to the main app.
//ConfigurationOverviewController controller = loader.getController();
//controller.setMainApp(this);
} catch (IOException e) {
e.printStackTrace();
}
}
另一个解决方案可以是下面的一个(即使前两个也可以)。从FMXL文件中删除fx:controller
,并按如下方式加载:
public void showConfigurationOverview() {
// Give the controller access to the main app.
ConfigurationOverviewController controller = new ConfigurationOverviewController(this);
root.setCenter(controller.getConfigurationOverview());
}
并按如下方式更改控制器:
public class ConfigurationOverviewController {
private AnchorPane configurationOverview;
private MainApp mainApp;
@FXML
private TableView configurationTable;
public ConfigurationOverviewController(MainApp pMain) {
mainApp = pMain;
FXMLLoader loader = new FXMLLoader(getClass().getResource("YOUR_FXML"));
loader.setController(this);
try {
configurationOverview = (AnchorPane)loader.load();
} catch (IOException e) {
e.printStackTrace();
}
}
public AnchorPane getConfigurationOverview() {
return configurationOverview;
}
@FXML
private void initialize() {
// Do your stuff with mainApp
configurationTable.setItems(mainApp.getConfigurationData());
}
}
编辑
这实际上是来自的解决方案。我也有类似的问题,但我发现我的控制器将指向MainApp的链接设为空。这就是我制作linkstatic
的原因。在此之后,我没有得到任何NullPointerException
。
也许这会有帮助
public class LoginController {
@FXML
private Label passwordLabl;
@FXML
private TextField passwordTexF;
public static WordLernApp wordLernApp;
public LoginController() {
LoginController.wordLernApp = null;
}
public void setWordLernApp(WordLernApp wordLernApp) {
LoginController.wordLernApp = wordLernApp;
}
除了考虑所有需要特殊处理的类之外,您还可以使用接口或公共基类。这将允许您对需要访问应用程序类的多个类使用相同的逻辑<代码>对象控制器;尝试{controller=clazz.newInstance();}(ReflectiveOperationException ex){throw new RuntimeException(ex);}if(controller instanceof MyType)((MyType)controller.setMain(this);返回控制器代码>使用依赖注入框架甚至可以更进一步…根据您的编辑编辑我的。更一般的是,如果您使用@mrmcwolf解决方案,只需添加configurationTable.setItems(mainApp.getConfigurationData())
在控制器的初始化方法中ConfigurationOverviewController
。谢谢,我也这么做了。然而,在@mrmcwolf的解决方案中,我有一份来自Intellij的报告指出,initialize()
方法现在从未使用过。这是正常的还是只是IDE的一个错误?因为应用程序似乎工作正常。您添加了@FXML注释吗?是的,当然。你可以从这里查到
public class LoginController {
@FXML
private Label passwordLabl;
@FXML
private TextField passwordTexF;
public static WordLernApp wordLernApp;
public LoginController() {
LoginController.wordLernApp = null;
}
public void setWordLernApp(WordLernApp wordLernApp) {
LoginController.wordLernApp = wordLernApp;
}