web-dev-qa-db-ja.com

コントローラクラスのJavaFXアプリケーションで画面を交換する方法は?

JavaFXプロジェクトに3つのファイルがある場合。 FXMLファイル、FXMLのコントローラー、およびアプリケーションクラス。コントローラーはボタンのクリック(完全に正常に機能します)に応答して、そのクリックで画面を変更します(通常はstage.setScreen()で行われます)。ステージへの参照はありません(アプリケーションクラスのstart(Stage)に渡されます)。

アプリケーションサンプル:

public class JavaFXApplication4 extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("Sample.fxml"));

        Scene scene = new Scene(root);

        stage.setScene(scene);
        stage.show();
    }

    /**
     * The main() method is ignored in correctly deployed JavaFX application.
     * main() serves only as fallback in case the application can not be
     * launched through deployment artifacts, e.g., in IDEs with limited FX
     * support. NetBeans ignores main().
     *
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }
}

FXMLサンプル:

<?xml version="1.0" encoding="UTF-8"?>

<?import Java.lang.*?>
<?import Java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<AnchorPane id="AnchorPane" prefHeight="200.0" prefWidth="320.0"  xmlns:fx="http://javafx.com/fxml" fx:controller="javafxapplication4.SampleController">
  <children>
  <Button id="button" fx:id="nextScreen" layoutX="126.0" layoutY="90.0" onAction="#handleButtonAction" text="Next Screen" />
  <Label fx:id="label" layoutX="126.0" layoutY="120.0" minHeight="16.0" minWidth="69.0" />
  </children>
</AnchorPane>

コントローラーのサンプル:

public class SampleController implements Initializable {

    @FXML
    private Label label;

    @FXML
    private void handleButtonAction(ActionEvent event) {
        System.out.println("You clicked me!");
        label.setText("Hello World!");

        // Here I want to swap the screen!
    }

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        // ...
    }    
}
19
B Y E
@FXML
private void handleButtonAction(ActionEvent event) {
    System.out.println("You clicked me!");
    label.setText("Hello World!");
    //Here I want to swap the screen!

    Stage stageTheEventSourceNodeBelongs = (Stage) ((Node)event.getSource()).getScene().getWindow();
    // OR
    Stage stageTheLabelBelongs = (Stage) label.getScene().getWindow();
    // these two of them return the same stage
    // Swap screen
    stage.setScene(new Scene(new Pane()));
}
29
Uluk Biy

Javaに入り、同じことを解決しようとしたときに、この古い質問を見つけました。スイッチ間のコンテンツをシーンに記憶させたいので、受け入れられた回答を使用できませんでした。シーンを切り替えると、再度インスタンス化されます(以前の状態が失われます)。

とにかく、受け入れられた答えと 同様の質問への答え は、状態を失うことなくシーンを切り替える方法についてのヒントを私に与えました。主なアイデアは、シーンのインスタンスを別のコントローラーに挿入することです。これにより、コントローラーは新しいシーンを何度もインスタンス化する必要がなく、既存のインスタンスを(その状態とともに)使用できます。

だからここにシーンをインスタンス化するメインクラスがあります:

public class Main extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        // getting loader and a pane for the first scene. 
        // loader will then give a possibility to get related controller
        FXMLLoader firstPaneLoader = new FXMLLoader(getClass().getResource("firstLayout.fxml"));
        Parent firstPane = firstPaneLoader.load();
        Scene firstScene = new Scene(firstPane, 300, 275);

        // getting loader and a pane for the second scene
        FXMLLoader secondPageLoader = new FXMLLoader(getClass().getResource("secondLayout.fxml"));
        Parent secondPane = secondPageLoader.load();
        Scene secondScene = new Scene(secondPane, 300, 275);

        // injecting second scene into the controller of the first scene
        FirstController firstPaneController = (FirstController) firstPaneLoader.getController();
        firstPaneController.setSecondScene(secondScene);

        // injecting first scene into the controller of the second scene
        SecondController secondPaneController = (SecondController) secondPageLoader.getController();
        secondPaneController.setFirstScene(firstScene);

        primaryStage.setTitle("Switching scenes");
        primaryStage.setScene(firstScene);
        primaryStage.show();
    }
}

そしてここに両方の​​コントローラーがあります:

public class FirstController {

    private Scene secondScene;

    public void setSecondScene(Scene scene) {
        secondScene = scene;
    }

    public void openSecondScene(ActionEvent actionEvent) {
        Stage primaryStage = (Stage)((Node)actionEvent.getSource()).getScene().getWindow();
        primaryStage.setScene(secondScene);
    }
}

うん、2番目のものは同じに見えます(一部のロジックはおそらく共有できますが、現在の状態は概念の証明として十分です)

public class SecondController {

    private Scene firstScene;

    public void setFirstScene(Scene scene) {
        firstScene = scene;
    }

    public void openFirstScene(ActionEvent actionEvent) {    
        Stage primaryStage = (Stage)((Node)actionEvent.getSource()).getScene().getWindow();
        primaryStage.setScene(firstScene);
    }
}
13
WallTearer

あなたもこのように試すことができます。

public void onBtnClick(ActionEvent event) {
    try {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("login.fxml"));
        Stage stage = (Stage) btn.getScene().getWindow();
        Scene scene = new Scene(loader.load());
        stage.setScene(scene);
    }catch (IOException io){
        io.printStackTrace();
    }

}
2
Abdul.Moqueet