FXML切り替えによる画面遷移
MementoWeaver開発記(3)
JavaFXでの画面遷移の実現方法について、JavaFX SamplesのFXML-LoginDemoを手本としてみる。
サンプルのソースはこんな感じ(重要な箇所のみを一部抜粋)。
まずはアプリケーションクラス(Main)側。
package demo; // snip! public class Main extends Application { // snip! @Override public void start(Stage primaryStage) { try { stage = primaryStage; stage.setTitle("FXML Login Sample"); stage.setMinWidth(MINIMUM_WINDOW_WIDTH); stage.setMinHeight(MINIMUM_WINDOW_HEIGHT); gotoLogin(); primaryStage.show(); } catch (Exception ex) { Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); } } // snip! private void gotoProfile() { try { ProfileController profile = (ProfileController) replaceSceneContent("Profile.fxml"); profile.setApp(this); } catch (Exception ex) { Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); } } private void gotoLogin() { try { LoginController login = (LoginController) replaceSceneContent("Login.fxml"); login.setApp(this); } catch (Exception ex) { Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); } } private Initializable replaceSceneContent(String fxml) throws Exception { FXMLLoader loader = new FXMLLoader(); InputStream in = Main.class.getResourceAsStream(fxml); loader.setBuilderFactory(new JavaFXBuilderFactory()); loader.setLocation(Main.class.getResource(fxml)); AnchorPane page; try { page = (AnchorPane) loader.load(in); } finally { in.close(); } Scene scene = new Scene(page, 800, 600); stage.setScene(scene); stage.sizeToScene(); return (Initializable) loader.getController(); } }
次は、コントローラクラス(LoginController)側
/* * Copyright (c) 2008, 2012 Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * * This file is available and licensed under the following license: * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the distribution. * - Neither the name of Oracle Corporation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package demo; // snip! public class LoginController extends AnchorPane implements Initializable { // snip! public void setApp(Main application){ this.application = application; } @Override public void initialize(URL location, ResourceBundle resources) { errorMessage.setText(""); userId.setPromptText("demo"); password.setPromptText("demo"); } public void processLogin(ActionEvent event) { if (application == null){ // We are running in isolated FXML, possibly in Scene Builder. // NO-OP. errorMessage.setText("Hello " + userId.getText()); } else { if (!application.userLogging(userId.getText(), password.getText())){ errorMessage.setText("Username/Password is incorrect"); } } } }
要するにすごくざっくりと言うと、こんな流れか。
- MainはLogin.fxmlをロードしてシーンコンテンツを置き換える(replaceSceneContent)
- Mainは置き換えたシーンのコントローラクラス(この場合はLoginController)をLoaderから得る
- Mainはコントローラクラス(この場合はLoginController)に自身を登録する
- LoginControllerは自身のイベントハンドリングの中で、登録されたMainオブジェクトを使用する(Mainオブジェクトをアプリケーション内の共有オブジェクトのコンテナとして使っている)。
コントローラクラス側でAnchorPaneをextendsしていたり、Initializableをimplementsしている理由はまだ理解できていないが、細かいことは後で考える(笑)。
ひとまずMainMenu→InstallMaterialの画面遷移が実装できたのでGitHubにcommitしておく。