Код, который я не понимаю о переключении сцен в JavaFX и SceneBuilder

После некоторого поиска в Google я решил, что могу изменить сцены, оставаясь на том же этапе, назначив этот метод кнопке:

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

Я не понимаю вторую строку, хотя. Что означает этап и узел в скобках? Это какой-то тип кастинга? Относится ли это как-то к "первичной" стадии? Я буду очень благодарен, если кто-то сможет полностью объяснить эту строку или сказать мне, какой материал я пропустил.

1 ответ

Решение

Синтаксис, в котором тип помещается в скобки перед выражением, является понижением, что хорошо объясняется здесь и здесь. Если вы расширите код, это может быть понятнее:

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 вообще: почему бы просто не заменить root из существующих Scene? Для этого вы можете сделать

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"))));
Другие вопросы по тегам