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:为什么不直接替换现有 Sceneroot?为此你可以做

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"))));