麻烦将参数传递给JavaFx中的控制器类

时间:2016-04-18 18:20:49

标签: java javafx fxml

我正在尝试在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; }
}

LoginController类:

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

}

TestApplication类:

    // 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();

1 个答案:

答案 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的方法,这可以产生更强大的代码。