JavaFX和SceneBuilder中切换场景我看不懂的一段代码
A code I don't understand about switching scenes in JavaFX and SceneBuilder
经过一些谷歌搜索,我发现我可以通过将此方法分配给按钮来更改场景,同时保持在同一阶段:
Parent root = FXMLLoader.load(getClass().getResource("view/bambam"));
Stage stage= (Stage) ((Node) event.getSource()).getScene().getWindow();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
虽然我不明白第二行。括号中的阶段和节点是什么意思?这是某种类型的铸造吗?它是否以某种方式引用 "primary" 阶段?如果有人能完整解释这一行或告诉我我错过了什么,我将不胜感激。material。
类型放在表达式前面的括号中的语法是向下转换,解释得很好here and here。如果展开代码,可能会更清晰:
Parent root = FXMLLoader.load(getClass().getResource("view/bambam"));
// get the source of the event
Object eventSource = event.getSource();
// the event only knows its source is some kind of object, however, we
// registered this listener with a button, which is a Node, so we know
// the actual runtime type of the source must be Button (which is a Node)
// So tell the compiler we are confident we can treat this as a Node:
Node sourceAsNode = (Node) eventSource ;
// get the scene containing the Node (i.e. containing the button):
Scene oldScene = sourceAsNode.getScene();
// get the window containing the scene:
Window window = oldScene.getWindow();
// Again, the Scene only knows it is in a Window, but we know we specifically
// put it in a stage. So we can downcast the Window to a Stage:
Stage stage = (Stage) window ;
// Equivalently, just omitting all the intermediate variables:
// Stage stage= (Stage) ((Node) event.getSource()).getScene().getWindow();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
恕我直言,这段代码写得很糟糕。首先,向下转型在某种程度上回避了通常的编译时类型检查,依靠我们自己对编码逻辑的分析来避免运行时异常。因此,最好尽可能避免使用它。
在这种情况下,您声明此代码是使用按钮注册的处理程序的一部分。因此,事件的来源是按钮。因此,我们可以只使用现有的引用,而不是通过所有这些步骤来取回对按钮的引用。换句话说,你有这样的东西:
button.setOnAction(event -> {
Parent root = FXMLLoader.load(getClass().getResource("view/bambam"));
Stage stage= (Stage) ((Node) event.getSource()).getScene().getWindow();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
});
这里((Node) event.getSource())
一定就是button
,所以可以直接化简为
button.setOnAction(event -> {
Parent root = FXMLLoader.load(getClass().getResource("view/bambam"));
Stage stage = (Stage) button.getScene().getWindow();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
});
其次,根本不需要替换 Scene
:为什么不直接替换现有 Scene
的 root
?为此你可以做
button.setOnAction(event -> {
Parent root = FXMLLoader.load(getClass().getResource("view/bambam"));
Scene scene = button.getScene();
scene.setRoot(root);
});
(显然 Stage
已经显示,因为用户点击了按钮,所以 stage.show()
是多余的)。
如果您愿意,可以将其简化为
button.setOnAction(event -> {
Parent root = FXMLLoader.load(getClass().getResource("view/bambam"));
button.getScene().setRoot(root);
});
甚至只是
button.setOnAction(event ->
button.getScene().setRoot(FXMLLoader.load(getClass().getResource("view/bambam"))));
经过一些谷歌搜索,我发现我可以通过将此方法分配给按钮来更改场景,同时保持在同一阶段:
Parent root = FXMLLoader.load(getClass().getResource("view/bambam"));
Stage stage= (Stage) ((Node) event.getSource()).getScene().getWindow();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
虽然我不明白第二行。括号中的阶段和节点是什么意思?这是某种类型的铸造吗?它是否以某种方式引用 "primary" 阶段?如果有人能完整解释这一行或告诉我我错过了什么,我将不胜感激。material。
类型放在表达式前面的括号中的语法是向下转换,解释得很好here and here。如果展开代码,可能会更清晰:
Parent root = FXMLLoader.load(getClass().getResource("view/bambam"));
// get the source of the event
Object eventSource = event.getSource();
// the event only knows its source is some kind of object, however, we
// registered this listener with a button, which is a Node, so we know
// the actual runtime type of the source must be Button (which is a Node)
// So tell the compiler we are confident we can treat this as a Node:
Node sourceAsNode = (Node) eventSource ;
// get the scene containing the Node (i.e. containing the button):
Scene oldScene = sourceAsNode.getScene();
// get the window containing the scene:
Window window = oldScene.getWindow();
// Again, the Scene only knows it is in a Window, but we know we specifically
// put it in a stage. So we can downcast the Window to a Stage:
Stage stage = (Stage) window ;
// Equivalently, just omitting all the intermediate variables:
// Stage stage= (Stage) ((Node) event.getSource()).getScene().getWindow();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
恕我直言,这段代码写得很糟糕。首先,向下转型在某种程度上回避了通常的编译时类型检查,依靠我们自己对编码逻辑的分析来避免运行时异常。因此,最好尽可能避免使用它。
在这种情况下,您声明此代码是使用按钮注册的处理程序的一部分。因此,事件的来源是按钮。因此,我们可以只使用现有的引用,而不是通过所有这些步骤来取回对按钮的引用。换句话说,你有这样的东西:
button.setOnAction(event -> {
Parent root = FXMLLoader.load(getClass().getResource("view/bambam"));
Stage stage= (Stage) ((Node) event.getSource()).getScene().getWindow();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
});
这里((Node) event.getSource())
一定就是button
,所以可以直接化简为
button.setOnAction(event -> {
Parent root = FXMLLoader.load(getClass().getResource("view/bambam"));
Stage stage = (Stage) button.getScene().getWindow();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
});
其次,根本不需要替换 Scene
:为什么不直接替换现有 Scene
的 root
?为此你可以做
button.setOnAction(event -> {
Parent root = FXMLLoader.load(getClass().getResource("view/bambam"));
Scene scene = button.getScene();
scene.setRoot(root);
});
(显然 Stage
已经显示,因为用户点击了按钮,所以 stage.show()
是多余的)。
如果您愿意,可以将其简化为
button.setOnAction(event -> {
Parent root = FXMLLoader.load(getClass().getResource("view/bambam"));
button.getScene().setRoot(root);
});
甚至只是
button.setOnAction(event ->
button.getScene().setRoot(FXMLLoader.load(getClass().getResource("view/bambam"))));