我从javafx开始,我在理解如何正确建模以下情况时遇到一些麻烦:
理想情况下,我想要一个main()
方法,以某种方式允许我打开LoginDialog
或者如果磁盘上已有用户/密码组合,则绕过登录并直接显示MainDialog
给用户。
我的主要问题是,当我运行Application.launch()
时,我希望提交一个Application
实例,并且在实现一个实例时,我无法控制其Stage
个对象创造,在这里为我创造了一个捕获22。
我可以创建一个LoginScene
和MainScene
但是我无法控制Stage
的标题等内容。
使用javafx解决此类问题的常用途径是什么?
由于
答案 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()
}
}