我正在尝试在JavaFX中构建一个简单的Login面板。我已经在stackoverflow上使用几乎相同的方法回顾了其他几个关于同样问题的帖子,但是,到目前为止,还没有弄清楚我做错了什么。我正在使用eclipse。
我的代码的这一部分一直有效,直到我尝试在LoginController类中访问login
变量。在initLogon
方法中,变量具有数据并且正在分配它,但是当我尝试从其他地方访问变量时它变为null。我的猜测是我在某个方面工作在LoginController类的两个独立实例中,一个由initdata
初始化而另一个不是,但是我无法弄清楚我在哪里失败了连接点。
以下是我的代码的相关部分:
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; }
}
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 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();
答案 0 :(得分:2)
问题完全在于事情发生的顺序。
当您调用FXMLLoader.load()
时,FXMLLoader
加载并解析fxml,创建控制器实例,注入@FXML
- 带注释的字段,并在控制器上调用initialize()
实例。然后它返回。
在您的代码中,您(必要)在 controller.initLogin()
方法完成后调用load
,并因此在调用initialize()
方法之后调用login
。因此initialize()
方法中login
为空。
快速解决方法只是执行取决于initLogin()
方法中fx:controller
的初始化。
可能更强大的修复是控制控制器的实例化。您可以通过从FXML文件中删除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);
}
}
上设置控制器来实现此目的:
fx:controller
或者,将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);
}
}
属性保留在FXML文件中并使用控制器工厂。如果要反射检查控制器类并在存在适当的方法或构造函数时设置值,则此方法更有用。但是,对于这个简单的情况,它可能看起来像:
LoginController
请注意,这两个示例都允许您使用构造函数参数定义Login
,而不是使用专门初始化select
的方法,这可以产生更强大的代码。