2 回答
TA贡献1921条经验 获得超9个赞
您目前拥有的有几个问题:
在您的
LoginScreen
构造函数中,您setWindow
使用尚未注入的字段的值进行调用:public LoginScreen(){ super(); setWindow(loginWindow); }
当控制器的构造函数正在执行时,不会注入任何 FXML 字段——意思
loginWindow
是null
. 原因不言而喻:必须FXMLLoader
先构建控制器实例,然后才能开始注入适当的字段。事件的顺序是:(1)实例化控制器,(2)注入字段,(3)调用初始化方法;我相信链接任何事件处理程序/更改侦听器都包含在第二步中。这意味着任何需要发生的关于 FXML 字段的初始化都应该在该
initialize
方法中完成。HomeScreen
您在使用 的构造函数中遇到了同样的问题super(homeWindow)
,尽管还有其他问题将在下一点中解决。除了试图访问构造函数中尚未注入的字段外,还有以下两个问题:
@FXML private static AnchorPane homeWindow = new AnchorPane();
第一个问题是您初始化了一个要注入的字段。永远不要这样做。一个好的经验法则是:如果该字段带有注释,
@FXML
则不要手动为其分配值。FXML 字段最终将被注入,这意味着您事先分配给它的任何值都将被简单地替换。这可能会导致一些细微的问题,因为任何引用先前值的代码都不会使用实际添加到场景图中的对象。另一个问题是你的领域是静态的。JavaFX 8+ 不支持注入静态字段。据我所知,它在旧版本中曾经是可能的,但这种行为从未得到官方支持(即是一个实现细节)。此外,让某些固有的基于实例(FXML+控制器)的东西设置一个会影响所有实例的静态字段是没有意义的。
一个额外的问题:当你制作
homeWindow
非静态时,你不能再使用super(homeWindow)
,因为在调用超级构造函数之前你不能引用它。
使用两个修改后的类应该允许您的代码运行:
LoginScreen.java:
public class LoginScreen extends ScreenController {
@FXML private AnchorPane loginWindow;
@FXML private Button goButton;
@Override
public void initialize(URL location, ResourceBundle resources) {
super.initialize(location, resources);
setWindow(loginWindow); // set window in initialize method
}
@FXML
public void goButtonPressed(ActionEvent event) throws IOException {
setScreen("Home");
System.out.println("Success.");
}
}
HomeScreen.java:
public class HomeScreen extends ScreenController {
@FXML private AnchorPane homeWindow;
@Override
public void initialize(URL location, ResourceBundle resources) {
super.initialize(location, resources);
setWindow(homeWindow); // set window in initialize method
}
}
但是不要使用:
window.getChildren().setAll(root);
在你的ScreenController#setScreen方法中——它会导致一个微妙的问题。您正在添加 aroot作为节点的子节点window。ScreenController但是,当发生这种情况时, (与新的相关联)的新实例root将具有其window == root. 换句话说,windowcreated with现在是created withLoginScreen的父级。根据更复杂的应用程序的设计方式,这可能导致“根”的嵌套越来越深。windowHomeScreen
也就是说,您已经有了另一种方法,您可以实际替换整个Scene. 正如您所说,您在那里遇到的问题是调整Stage大小以适应新的Scene. 这可以通过替换 的root而Scene不是Scene本身来解决:
window.getScene().setRoot(root);
TA贡献1859条经验 获得超6个赞
您可以在初始化期间获得 JavaFX 应用程序的主要阶段。其他场景类应该有一个带有 getter 和 setter 的 Stage 字段,这样您就可以通过它们的 Controller 传递主舞台。至于窗口调整大小,您可以通过在语句中添加getStage().getWidth()和来解决。getStage().getHeight()setScene()
我要指出的一个小例子:
public class MainClass extends Application {
@Override
public void start(Stage stage) throws Exception {
InputStream sceneStream = MainClass.class.getResourceAsStream("/fxml"+
"/newScene/main.fxml");
FXMLLoader loader = new FXMLLoader();
Parent root = loader.load(sceneStream);
Scene scene = new Scene(root);
stage.setTitle("App title");
NewScene controller = loader.getController();
controller.setMainStage(stage);
stage.setScene(scene, stage.getWidth(), stage.getHeight());
stage.show();
}
所以上面的函数从创建主阶段的MainClass开始。请注意中间部分与代码的其余部分有点分离,通过获取已加载的控制器,Scene我将阶段传递给它。您可以通过这种方式将舞台传递到所有场景。还要注意设置场景的部分,我在这里使用了两个从舞台中提取的参数;宽度和高度。除此之外,还有更多方法可以在主舞台上运行的几乎每个场景中获得舞台,只需执行以下操作:
@FXML private Button aButton;
public Button getAButton(){
return aButton;
}
Stage stage = (Stage) getAButton().getScene().getWindow();
Node这将适用于基于初级阶段的所有场景,并且无论类型如何,只需要在场景图中注册即可。
添加回答
举报