不在布局javafx中加载子节点

时间:2014-12-08 00:19:03

标签: spring javafx javafx-8

我试图为我的应用程序做一个简单的启动窗口。

    ClassLoader cachingClassLoader = new MyClassLoader(FXMLLoader.getDefaultClassLoader());
    URL resource = MainApp.class
            .getResource("/startupWindow.fxml").toURI().toURL();
    FXMLLoader loader = new FXMLLoader(resource);
    loader.setClassLoader(cachingClassLoader);
    BorderPane rootLayout = (BorderPane) loader.load();

    scene = new Scene(rootLayout,512,384);

    this.primaryStage.initStyle(StageStyle.UNDECORATED);
    this.primaryStage.setTitle(TITLE);
    this.primaryStage.setScene(scene);
    this.primaryStage.show();

     //configuration main layout and add it to the stage

不幸的是,启动后,应用程序显示启动窗口,但没有任何内容。在整个主布局的加载过程中,启动窗口内容为空。除此之外我没有例外。

我注意到在调用primaryStage.show()之后附加代码时会出现内容加载问题。并且在附加代码的末尾呈现布局内容,例如:

    this.primaryStage.setScene(scene);
    this.primaryStage.show();

    Thread.sleep(2000L);
    // Content is displayed,( after 2 seconds ).

我不知道如何让它发挥作用。任何建议都会有所帮助。

编辑:

我实际面临的问题是在加载Spring应用程序上下文时创建启动窗口。我一直在尝试在单独的线程中创建应用程序上下文,它只是挂起而没有异常发生。

编辑2:

经过一些调试后,我发现了一个异常:

org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'SomePresenter': Invocation of init method failed;
nested exception is java.lang.IllegalStateException: 
Not on FX application thread; currentThread = Thread-3

顺便说一句,应用程序遵循MVP设计模式,Spring应用程序上下文自动加载视图和演示者。

编辑3:

我创建新线程的代码是:

    Task loadingTask = new Task() {
    @Override
    protected ApplicationContext call() throws Exception {
        return new ClassPathXmlApplicationContext("./spring/application_context.xml");
    }
};

loadingTask.setOnSucceeded(event -> {
    context = (ApplicationContext)loadingTask.getValue();
    MainPresenter mainPresenter = (MainPresenter) context.getBean("MainPresenter");
    mainPresenter.getView().setPrimaryStage(primaryStage);
    scene = new Scene(mainPresenter.getView(), bounds.getWidth(), bounds.getHeight());
    scene.getStylesheets().add(getClass().getResource("/styles/styles.css").toExternalForm());
    this.primaryStage.setScene(scene);
});

new Thread(loadingTask).start();

2 个答案:

答案 0 :(得分:0)

start()方法在FX应用程序线程上执行,FX应用程序线程负责呈现UI并处理用户输入。它也是某些操作合法的唯一线程,例如访问场景图中的节点状态以及创建SceneStage s。

问题是您正在执行阻止此线程的代码,这意味着UI没有机会被渲染。如果您要执行非常耗时的(非UI)代码,则应在单独的线程中执行该代码,然后在完成时安排在FX应用程序线程上的UI上进行更新。

Task类专为此用例而设计。

所以你可以这样做:

public void start(Stage primaryStage) {
    primaryStage.initStyle(StageStyle.UNDECORATED);
    primaryStage.setTitle(TITLE);
    primaryStage.setScene(scene);
    primaryStage.show();

    Task<SomeDataType> startupTask = new Task<SomeDataType>() {
        @Override
        protected SomeDataType call() {
            SomeDataType result = ... ; // result of time-consuming operation
            return result ;
        }
    };

    startupTask.setOnSucceeded(event -> {
        // this is executed on the FX Application Thread
        SomeDataType result = startupTask.getValue();
        // update UI using result ...
    });

    new Thread(startupTask).start();
}

答案 1 :(得分:0)

如果可能,您应该检查JDK 1.8.0_40的EAP,因为它使您能够在后台任务中构建UI,据我了解他们正在尝试做什么(在JavaFX应用程序线程之外):

见他们的JIRA: https://javafx-jira.kenai.com/browse/RT-17716

在后台任务中构建UI在某些情况下确实有意义,特别是对于大型FXML文件,因为它很慢。

如果没有解决您的问题,您将必须检查您的Spring集成,您是否使用自定义FXMLLoader与构建器工厂/控制器工厂? Spring是在单独的线程中还是在JavaFX Application Thread中运行?