1 回答
TA贡献2003条经验 获得超2个赞
JavaFX 有一个“事件线程”,负责处理按钮点击、更新标签和任何其他与 GUI 相关的任务。当您调用时button.setOnAction(e -> doSomething());,当您按下按钮时,doSomething()发生在 JavaFX 线程上。在此运行期间,不会发生其他 GUI 事件。这意味着您的界面将完全冻结,从而导致糟糕的用户体验。
此外,您不能在 JavaFX 线程以外的任何线程上执行 GUI 操作,否则您将获得一个IllegalStateException. (试着打电话Executors.newSingleThreadExecutor().execute(() -> label.setText("hello"));看看这个在行动)
幸运的是,JavaFX 提供了解决这个问题的方法。
首先,也是最简单的方法,是在新线程中调用长时间运行的方法(可能使用ExecutorService上面的 s),当您需要修改接口时,将这些调用包装在对Platform.runLater(() -> updateInterface());. 这将发布updateInterface()到 GUI 线程,并允许它运行。
但是,这可能会很麻烦,因此首选方法是使用Service.
假设您的长时间运行的计算返回一个Double,您创建一个类 extending Service<Double>,覆盖它的createTask()方法,并在那里执行计算,如下所示:
public class CalculationService extends Service<Double> {
@Override
protected Task<Double> createTask() {
return new Task<Double>() {
@Override
protected Double call() throws Exception {
return doCalculation();
}
};
}
}
然后,在你的控制器中,声明一个private final CalculationService service = new CalculationService();
在您的控制器initialize()方法中,您可以将此服务的输出绑定到您想要的任何内容。例如:
calculationDisplayLabel.textProperty().bind(Bindings.createStringBinding(service.valueProperty()));
// continuously updates the label whenever the service calculates a new value
然后,每当您决定要重新开始计算时,service.restart()如果进程正在运行,您可以调用中断进程,并从头开始。
如果要在值更改时调用代码,请向服务的值添加一个侦听器。例如,如果您希望它在完成后立即重新计算,请调用:
service.valueProperty().addListener((obs, old, newValue) -> service.restart());
添加回答
举报