嘿,我从JavaFX视图提交时遇到了问题。在提交我想实现以下链:
- 将光标更改为等待符号
- 设置标签文本"正在加载…"
- 进行API调用
- 将标签文本设置为"已完成,请点击刷新"
- 将光标设置回默认值
我想这样做,因为API调用确实锁定了(web)视图的其余部分,我不希望用户点击并导致程序崩溃。我写了这个代码来实现我上面描述的事件链
Button submit = new Button();
submit.setPadding(new Insets(5));
submit.setText("Submit");
submit.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
try {
scene.setCursor(Cursor.WAIT);
label.setText("loading...");
System.out.println("loading");
model.newRootNode(searchIndividual.getText(), Integer.valueOf(numberField.getText()));
// This makes the API call
System.out.println("finished");
label.setText("Done! Please hit 'Refresh'");
scene.setCursor(Cursor.DEFAULT);
} catch (Exception e) {
e.printStackTrace();
}
}
});
vbox.getChildren().add(submit);
使用eclipse调试器,我无法使标签文本更改可见,但光标似乎可以工作。此外,我使用sysouts()
来检查API调用前后的代码是否得到执行,并打印loading
和finished
。标签被设置为Done! Please hit 'Refresh'
,如果我以后不重写它的话,它会将光标设置为cursor.WAIT
为什么API调用之前的代码似乎没有执行?或者说给出视觉反馈?
从ui线程调用事件处理程序,在更改ui内容后,该线程无法自由刷新场景。在另一个线程上执行长时间运行的操作,并让ui线程继续执行它的工作来修复此问题。您可以简单地使用Platform.runLater
从您启动的非ui线程对ui进行更改,或者使用Task
,它的设计目的是完成这样的工作:
Task<Void> task = new Task<Void>() {
@Override
protected Void call() throws Exception {
// makes the long-running API call
return null;
}
};
task.setOnRunning((WorkerStateEvent event) -> {
// disable ui
});
task.setOnCancelled((WorkerStateEvent event) -> {
// reenable ui
// handle cancel
});
task.setOnSucceeded((WorkerStateEvent event) -> {
// reenable ui
// handle succeed
});
task.setOnFailed((WorkerStateEvent event) -> {
// reenable ui
// handle failed task e.g.:
System.err.println("Oops, Error:");
task.getException().printStackTrace(System.err);
});
Thread t = new Thread(task);
// thread shouldn't prevent program shutdown
t.setDaemon(true);
t.start();
还要注意,在处理异常的方式中,如果抛出异常,ui将不会再次解锁,因为代码的这一部分位于发生异常的块内。