问题是(可能;您没有显示空指针异常的来源)您仅设置局部变量root
and controller
,然后让它们超出范围。
请记住,Java 以按值传递的方式处理方法参数:因此该方法会创建root
和controller
引用的本地副本。当您的方法调用时
root = loader.load();
controller = loader.getController();
它只是更新本地引用,而不是传递给方法的引用。所以如果你这样做
Parent root = null ;
MyController controller = null ;
loadFXML(root, controller, "Main.fxml");
System.out.println(root);
System.out.println(controller);
你会看到价值观null
。
一种解决方法是传入对象的可变包装器,并更新这些包装器。ObjectProperty
为此工作:
<R, C> void loadFXML(String path, ObjectProperty<R> root, ObjectProperty<C> controller)
{
URL fxmlUrl = this.getClass().getResource( path );
FXMLLoader loader = new FXMLLoader(fxmlUrl);
try
{
root.set(loader.load());
controller.set(loader.getController());
}
catch(IOException ioe)
{
ioe.printStackTrace();
}
}
另一种选择是创建一个封装这两个值的类并返回它的一个实例:
public class ViewController<V,C> {
private final V view ;
private final C controller ;
public ViewController(V view, C controller) {
this.view = view ;
this.controller = controller ;
}
public V getView() {
return view ;
}
public C getController() {
return controller ;
}
}
接着
<R, C> ViewController<R, C> loadFXML(String path)
{
URL fxmlUrl = this.getClass().getResource( path );
FXMLLoader loader = new FXMLLoader(fxmlUrl);
try
{
R root = loader.load();
C controller = loader.getController();
return new ViewController<R,C>(root, controller);
}
catch(IOException ioe)
{
ioe.printStackTrace();
throw new UncheckedIOException(ioe); // this is likely fatal, so just throw an unchecked exception
}
}
但是,您是否在冗长方面得到任何节省是有争议的:
ViewController<Parent, MyController> viewController = loadFXML("Main.fxml");
Parent root = viewController.getView();
MyController controller = viewController.getController();
最后的观察是,在几乎所有用例中,您实际上只是在之后才对控制器进行任何重要的工作。您通常只需将视图设置为场景的根,或将其添加到另一个布局窗格。Consumer<R>
您可以通过让方法接受 a并返回控制器来利用这一点(在 Java 8 中) :
public <R, C> C loadFXML(Consumer<R> rootHandler, String path) {
URL fxmlUrl = this.getClass().getResource( path );
FXMLLoader loader = new FXMLLoader(fxmlUrl);
try
{
R root = loader.load();
C controller = loader.getController();
rootHandler.accept(root);
return controller ;
}
catch(IOException ioe)
{
ioe.printStackTrace();
throw new UncheckedIOException(ioe); // this is likely fatal, so just throw an unchecked exception
}
}
你会使用类似的东西来调用它
Scene scene = new Scene();
MyController controller = loadFXML(scene::setRoot, "Main.fxml");