您好我想展示后台任务的进度。
@FXML
private void addOfficeBarrierSelect() {
App.getInstance().showProgressIndicator(myController);
Task<Void> task = new Task<Void>() {
@Override
protected Void call() throws Exception {
ScreensController colllectScreenController = new ScreensController();
colllectScreenController.loadScreen(Screens.ADD_OFFICE_BARRIER);
colllectScreenController.setScreen(Screens.ADD_OFFICE_BARRIER);
content.setContent(null);
content.setContent(colllectScreenController);
return null;
}
@Override
protected void succeeded() {
App.getInstance().hideProgressIndicator(myController);
}
@Override
protected void failed() {
super.failed();
App.getInstance().hideProgressIndicator(myController);
}
};
new Thread(task).start();
}
以下代码是我在我的应用程序中使用的进度弹出窗口。
public void showProgressIndicator(ScreensController myController) {
myController.setDisable(true);
if (popupProgressIndicator == null) {
JFXSpinner spinner = new JFXSpinner();
spinner.setLayoutX(0);
spinner.setLayoutY(0);
spinner.setPrefHeight(200);
spinner.setPrefWidth(200);
popupProgressIndicator = new Popup();
popupProgressIndicator.getContent().add(spinner);
}
if (!popupProgressIndicator.isShowing()) {
popupProgressIndicator.show(primaryStage);
popupProgressIndicator.centerOnScreen();
}
}
public void hideProgressIndicator(ScreensController myController) {
myController.setDisable(false);
if (popupProgressIndicator.isShowing())
popupProgressIndicator.hide();
}
问题是当我运行应用程序时,没有发生FX应用程序线程异常..
Exception in thread "Thread-6" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-6
并指向Task线程内的void call()方法。
有没有解决方案..
James_D
解决方案实际上对我有用。但我必须将代码更改为此。
showProgressIndicator(myController);
Task<FXMLLoader> task = new Task<FXMLLoader>() {
@Override
protected FXMLLoader call() throws Exception {
FXMLLoader loader = new FXMLLoader(App.class.getResource(Screens.ADD_MEMBER));
return loader;
}
@Override
protected void succeeded() {
super.succeeded();
hideProgressIndicator(myController);
}
@Override
protected void failed() {
super.failed();
hideProgressIndicator(myController);
}
};
new Thread(task).start();
再次更改代码后,进度不显示。只需跟随@james_D anwser。
答案 0 :(得分:2)
您正在获取异常,因为您正在从后台线程更新UI。您需要从FX应用程序线程更新UI。如果您需要在Platform.runLater()
方法执行期间进行增量更新,或者(在这种情况下似乎:我不确定{{1}是什么,您可以通过调用call()
来执行此操作如果您只需要在任务完成后更新UI,则可以使用loadScreen
方法更新UI任务:
setScreen
答案 1 :(得分:-1)
这是一个简单的例子来说明如何使用AnimationTimer和一些状态(busy和labelText)来完成它。在动画计时器的每个刻度上修改按钮和标签的状态。而任务是更新状态(不是UI)的东西。
当然,这里的状态需要同步,因此您可能希望实现一个postMessage()方法,该方法允许任务将状态报告回UI,然后将其添加到消息队列中,然后由AnimationTimer消耗。但是,下面提供的代码仅用于 ILLUSTRATIVE PURPOSES 。关键是要强调您无法从非UI线程更新UI控件。
我还添加了一个ProgressBar,并将其progressProperty绑定到任务的progressProperty。因此,有两种方法可以为您管理更新:)
使用progressProperty()绑定可能是最好的。在该实例中不需要AnimationTimer。但是,如果你实现了这种方式,那么你应该在UI线程上实现一个消息队列,并通过postMessage()方法同步状态更改。
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Progress extends Application {
String labelText = "Foobar";
boolean busy = false;
@Override
public void start(Stage stage) {
Label label = new Label();
ProgressBar progress = new ProgressBar();
progress.setProgress(0);
Button button = new Button("Test");
button.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
System.out.println("Button has been pressed...");
Task<Void> task = new Task<Void>() {
@Override
protected Void call() throws Exception {
busy = true;
System.out.println("Calling long running task...");
for (int i = 0; i <= 100; i++) {
labelText = "Progress: " + i;
updateProgress(i, 100);
Thread.sleep(50);
}
return null;
}
@Override
protected void succeeded() {
System.out.println("Succeeded");
busy = false;
}
@Override
protected void failed() {
System.out.println("Failed");
}
};
progress.progressProperty().bind(task.progressProperty());
Thread thread = new Thread(task);
thread.start();
}
});
AnimationTimer timer = new AnimationTimer() {
@Override
public void handle(long now) {
label.setText(labelText);
button.setDisable(busy);
}
};
timer.start();
VBox vbox = new VBox(label, progress, button);
Scene scene = new Scene(vbox, 400, 300);
stage.setTitle("Test");
stage.setScene(scene);
stage.show();
}
}
注意,任务必须对控件无效,只有状态。
另见:https://docs.oracle.com/javafx/2/threads/jfxpub-threads.htm
这个问题:JavaFX : How to pass value from background thread to JavaFX UI thread with Task。