我试图为我的应用程序做一个简单的启动窗口。
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();
答案 0 :(得分:0)
start()
方法在FX应用程序线程上执行,FX应用程序线程负责呈现UI并处理用户输入。它也是某些操作合法的唯一线程,例如访问场景图中的节点状态以及创建Scene
和Stage
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中运行?