无法将参数传递给 JavaFx 中的控制器 class
Trouble passing arguments to controller class in JavaFx
我正在尝试使用 JavaFX 构建一个简单的登录面板。我已经在 Whosebug 上使用几乎相同的方法查看了其他几篇关于同一问题的帖子,但到目前为止,我还没有弄清楚我做错了什么。我正在使用日食。
我的这部分代码一直有效,直到我尝试访问我的 LoginController class 中的 login
变量。在 initLogon
方法中,变量有数据并正在分配它,但是当我尝试从其他地方访问变量时,它为空。我的猜测是我以某种方式在 LoginController class 的 2 个独立实例中工作,一个由 initdata
初始化,另一个不是,但我不知道我在哪里未能连接点。
以下是我的代码的相关部分:
登录class:
public class Login {
private Scene scene;
private GsonBuilder gsonBuilder;
private Config config;
private Token token; //auth token from json server
public Login(Scene scene, GsonBuilder gsonBuilder, Config config, Token token){
this.scene = scene;
this.gsonBuilder = gsonBuilder;
this.config = config;
this.token = token;
}
public void showLoginScreen(){
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("LoginScreen.fxml"));
scene.setRoot((Parent) loader.load());
LoginController controller = loader.<LoginController>getController();
controller.initLogin(this);
} catch (Exception ex) {
Logger.getLogger(Login.class.getName()).log(Level.SEVERE, null, ex);
}
}
public Config getConfig(){ return this.config; }
public Token getToken(){ return this.token; }
public GsonBuilder getGsonBuilder(){ return this.gsonBuilder; }
}
登录控制器class:
public class LoginController implements Initializable {
//Removed FXML stuff for brevity
private Login login;
public void initLogin(final Login login){
this.login = login;
//Troubleshooting line **works**
System.out.println("After initLogin, but from initLogin " +
this.login.getConfig().getAppUsername());
}
@Override
public void initialize(URL location, ResourceBundle resources) {
assert txtUsername != null : "fx:id=\"txtUsername\" was not injected: check your FXML file 'LoginScreen.fxml'.";
assert txtPassword != null : "fx:id=\"txtPassword\" was not injected: check your FXML file 'LoginScreen.fxml'.";
assert btnLogin != null : "fx:id=\"btnLogin\" was not injected: check your FXML file 'LoginScreen.fxml'.";
assert btnCancel != null : "fx:id=\"btnCancel\" was not injected: check your FXML file 'LoginScreen.fxml'.";
System.out.println(this.getClass().getSimpleName() + ".initialize");
// Troubleshoot line **Does not work**
System.out.println("During initialization " +
this.login.getConfig().getAppUsername());
//other stuff happens below here
}
// Other functions are here
}
测试应用程序class:
// class extends Application above this (removed for brevity)
Stage loginStage = new Stage(StageStyle.UNDECORATED);
Scene scene = new Scene(new AnchorPane());
Login appLogin = new Login(scene, this.gsonBuilder, this.config, this.token);
appLogin.showLoginScreen();
loginStage.setScene(scene);
loginStage.show();
问题完全在于事情发生的顺序。
当您调用 FXMLLoader.load()
时,FXMLLoader
加载并解析 fxml,创建控制器实例,注入 @FXML
-注释字段,并调用 initialize()
控制器实例。然后 returns.
在您的代码中,您(必然)在 load
方法完成后调用 controller.initLogin()
,因此在 initialize()
方法完成后已被调用。因此 login
在 initialize()
方法中为 null。
快速解决方法是在 initLogin()
方法中执行依赖于 login
的初始化。
可能更可靠的修复方法是控制控制器的实例化。您可以通过从 FXML 文件中删除 fx:controller
属性、自己实例化控制器并在 FXMLLoader
:
上设置控制器来实现此目的
public void showLoginScreen(){
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("LoginScreen.fxml"));
LoginController controller = new LoginController();
controller.initLogin(this);
loader.setController(controller);
scene.setRoot((Parent) loader.load());
} catch (Exception ex) {
Logger.getLogger(Login.class.getName()).log(Level.SEVERE, null, ex);
}
}
或者,在 FXML 文件中保留 fx:controller
属性并使用控制器工厂。如果您想反思性地检查控制器 class 并在存在适当的方法或构造函数时设置一个值,则此方法更有用。然而,对于这个简单的例子,它可能看起来像:
public void showLoginScreen(){
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("LoginScreen.fxml"));
loader.setControllerFactory((Class<?> controllerType) -> {
if (controllerType == LoginController.class) {
LoginController controller = new LoginController();
controller.initLogin(this);
return controller ;
} else {
try {
return controllerType.newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
});
scene.setRoot((Parent) loader.load());
LoginController controller = loader.<LoginController>getController();
controller.initLogin(this);
} catch (Exception ex) {
Logger.getLogger(Login.class.getName()).log(Level.SEVERE, null, ex);
}
}
请注意,这两个示例都允许您使用构造函数参数定义 LoginController
,而不是使用专门初始化 Login
的方法,这样可以生成更健壮的代码。
我正在尝试使用 JavaFX 构建一个简单的登录面板。我已经在 Whosebug 上使用几乎相同的方法查看了其他几篇关于同一问题的帖子,但到目前为止,我还没有弄清楚我做错了什么。我正在使用日食。
我的这部分代码一直有效,直到我尝试访问我的 LoginController class 中的 login
变量。在 initLogon
方法中,变量有数据并正在分配它,但是当我尝试从其他地方访问变量时,它为空。我的猜测是我以某种方式在 LoginController class 的 2 个独立实例中工作,一个由 initdata
初始化,另一个不是,但我不知道我在哪里未能连接点。
以下是我的代码的相关部分:
登录class:
public class Login {
private Scene scene;
private GsonBuilder gsonBuilder;
private Config config;
private Token token; //auth token from json server
public Login(Scene scene, GsonBuilder gsonBuilder, Config config, Token token){
this.scene = scene;
this.gsonBuilder = gsonBuilder;
this.config = config;
this.token = token;
}
public void showLoginScreen(){
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("LoginScreen.fxml"));
scene.setRoot((Parent) loader.load());
LoginController controller = loader.<LoginController>getController();
controller.initLogin(this);
} catch (Exception ex) {
Logger.getLogger(Login.class.getName()).log(Level.SEVERE, null, ex);
}
}
public Config getConfig(){ return this.config; }
public Token getToken(){ return this.token; }
public GsonBuilder getGsonBuilder(){ return this.gsonBuilder; }
}
登录控制器class:
public class LoginController implements Initializable {
//Removed FXML stuff for brevity
private Login login;
public void initLogin(final Login login){
this.login = login;
//Troubleshooting line **works**
System.out.println("After initLogin, but from initLogin " +
this.login.getConfig().getAppUsername());
}
@Override
public void initialize(URL location, ResourceBundle resources) {
assert txtUsername != null : "fx:id=\"txtUsername\" was not injected: check your FXML file 'LoginScreen.fxml'.";
assert txtPassword != null : "fx:id=\"txtPassword\" was not injected: check your FXML file 'LoginScreen.fxml'.";
assert btnLogin != null : "fx:id=\"btnLogin\" was not injected: check your FXML file 'LoginScreen.fxml'.";
assert btnCancel != null : "fx:id=\"btnCancel\" was not injected: check your FXML file 'LoginScreen.fxml'.";
System.out.println(this.getClass().getSimpleName() + ".initialize");
// Troubleshoot line **Does not work**
System.out.println("During initialization " +
this.login.getConfig().getAppUsername());
//other stuff happens below here
}
// Other functions are here
}
测试应用程序class:
// class extends Application above this (removed for brevity)
Stage loginStage = new Stage(StageStyle.UNDECORATED);
Scene scene = new Scene(new AnchorPane());
Login appLogin = new Login(scene, this.gsonBuilder, this.config, this.token);
appLogin.showLoginScreen();
loginStage.setScene(scene);
loginStage.show();
问题完全在于事情发生的顺序。
当您调用 FXMLLoader.load()
时,FXMLLoader
加载并解析 fxml,创建控制器实例,注入 @FXML
-注释字段,并调用 initialize()
控制器实例。然后 returns.
在您的代码中,您(必然)在 load
方法完成后调用 controller.initLogin()
,因此在 initialize()
方法完成后已被调用。因此 login
在 initialize()
方法中为 null。
快速解决方法是在 initLogin()
方法中执行依赖于 login
的初始化。
可能更可靠的修复方法是控制控制器的实例化。您可以通过从 FXML 文件中删除 fx:controller
属性、自己实例化控制器并在 FXMLLoader
:
public void showLoginScreen(){
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("LoginScreen.fxml"));
LoginController controller = new LoginController();
controller.initLogin(this);
loader.setController(controller);
scene.setRoot((Parent) loader.load());
} catch (Exception ex) {
Logger.getLogger(Login.class.getName()).log(Level.SEVERE, null, ex);
}
}
或者,在 FXML 文件中保留 fx:controller
属性并使用控制器工厂。如果您想反思性地检查控制器 class 并在存在适当的方法或构造函数时设置一个值,则此方法更有用。然而,对于这个简单的例子,它可能看起来像:
public void showLoginScreen(){
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("LoginScreen.fxml"));
loader.setControllerFactory((Class<?> controllerType) -> {
if (controllerType == LoginController.class) {
LoginController controller = new LoginController();
controller.initLogin(this);
return controller ;
} else {
try {
return controllerType.newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
});
scene.setRoot((Parent) loader.load());
LoginController controller = loader.<LoginController>getController();
controller.initLogin(this);
} catch (Exception ex) {
Logger.getLogger(Login.class.getName()).log(Level.SEVERE, null, ex);
}
}
请注意,这两个示例都允许您使用构造函数参数定义 LoginController
,而不是使用专门初始化 Login
的方法,这样可以生成更健壮的代码。