如何使用javafx在应用程序启动时运行多个不同阶段中的一个?

时间:2016-04-14 19:21:22

标签: java javafx javafx-2 javafx-8

我从javafx开始,我在理解如何正确建模以下情况时遇到一些麻烦:

理想情况下,我想要一个main()方法,以某种方式允许我打开LoginDialog或者如果磁盘上已有用户/密码组合,则绕过登录并直接显示MainDialog给用户。

我的主要问题是,当我运行Application.launch()时,我希望提交一个Application实例,并且在实现一个实例时,我无法控制其Stage个对象创造,在这里为我创造了一个捕获22。

我可以创建一个LoginSceneMainScene但是我无法控制Stage的标题等内容。

使用javafx解决此类问题的常用途径是什么?

由于

2 个答案:

答案 0 :(得分:1)

定义一个Application子类并放置逻辑来决定是否需要在start()方法中显示登录界面(启动逻辑的正确位置是恰当命名的{{1}方法,而不是start()方法):

main

如果你没有使用FXML,你只需定义类而不是FXML文件+控制器,用于"登录"和" main",但结构保持不变:

public class MyApplication extends Application {

    private boolean loggedIn ;

    @Override
    public void start(Stage primaryStage) {

        loggedIn = checkLoginFromDisk();

        while (! loggedIn) {
            FXMLLoader loginLoader = new FXMLLoader(getClass().getResource("path/to/login.fxml"));
            Parent loginRoot = loginLoader.load();
            LoginController loginController = loginLoader.getController();
            Scene loginScene = new Scene(loginRoot);
            primaryStage.setScene(loginScene);
            primaryStage.setTitle("Login");
            primaryStage.showAndWait();
            // check login from controller and update loggedIn...
        }

        FXMLLoader mainLoader = new FXMLLoader(getClass().getResource("path/to/main.fxml"));
        Parent mainRoot = mainLoader.load();
        Scene mainScene = new Scene(mainRoot);
        primaryStage.setScene(mainScene);
        primaryStage.setTitle("My Application");
        primaryStage.sizeToScene();
        primaryStage.show();
    }

    private boolean checkLoginFromDisk() {
        // ... etc
    }

    // for environments not supporting direct launch of JavaFX:
    public static void main(String[] args) {
        launch(args);
    }
}

public class LoginView {

    private final GridPane /* for example */ view ;

    public LoginView() {
        // setup UI, etc...
    }

    public Pane getView() {
        return view ;
    }

    public boolean checkLogin() {
        // etc...
    }
}

然后你的start方法看起来像

public class MainView {

    private BorderPane /* for example */ view ;

    public MainView() {
        // set up UI etc...
    }

    public Pane getView() {
        return view ;
    }
}

显然,您可以根据需要以多种方式重构(重用相同的登录类或fxml实例,对主视图使用不同的阶段等等)。

请注意,不需要使用传递给@Override public void start(Stage primaryStage) { loggedIn = checkLoginFromDisk(); while (! loggedIn) { LoginView loginView = new LoginView(); Scene loginScene = new Scene(loginView.getView()); primaryStage.setScene(loginScene); primaryStage.setTitle("Login"); primaryStage.showAndWait(); loggedIn = loginView.checkLogin(); } MainView mainView = new MainView(); Scene mainScene = new Scene(mainView.getView()); primaryStage.setScene(mainScene); primaryStage.setTitle("My Application"); primaryStage.sizeToScene(); primaryStage.show(); } 方法的阶段。因此,如果您希望独立类封装包含登录场景和主场景的舞台,您可以添加以下类:

start()

同样制作一个public class LoginStage extends Stage { private final LoginView loginView ; public LoginStage() { loginView = new LoginView(); setScene(new Scene(loginView.getView()); setTitle("Login"); } public boolean checkLogin() { return loginView.checkLogin(); } } 课程。 (在基于FXML的版本中,MainStage包含对LoginStage的引用,只是在构造函数中加载FXML而不是实例化LoginController类。)然后

LoginView

答案 1 :(得分:0)

这似乎与我正在寻找的非常相似。它遵循jns的建议。 不理想但不可怕:

class LoginScene(stage: Stage) extends Scene(new VBox()) {
  val vbox = this.getRoot.asInstanceOf[VBox]

  ...
}

class MainScene(stage: Stage) extends Scene(new VBox()) {
  val vbox = this.getRoot.asInstanceOf[VBox]

  ...
}

class ApplicationStartup extends Application {
  override def start(primaryStage: Stage): Unit = {
    val scene = if (...) new LoginScene(primaryStage) else new MainScene(primaryStage)
    primaryStage.setScene(scene)
    primaryStage.show()
  }
}

(代码以Scala表示)

或者,从问题的评论中可以看出,人们可以忽略primaryStage并随意创建我们自己的那些,这正是我从一开始就想要的:

class MainDialog extends Application {
  override def start(primaryStage: Stage): Unit = {
    val newStage = new Stage {
      setTitle("abcdef")
      setScene(new Scene(new Button("Hello World")))
    }
    newStage.show()
  }
}