我想在TilePane中加载最多九个面板。对于每个窗格,我必须首先运行内容计算(大约300ms),其次是构建面板(大约500ms)。我想要的是,有9个ProgressIndicators在计算后与每个面板进行交换。 我使用Platform.runlater命令以及服务类来试用它。结果总是一样的。 ProgressIndicator显示,但不是动画。几秒钟后,所有的面板一次。 有没有可能,指标是动画空洞时间,我可以一个接一个地交换它们?JavaFX在后台执行任务
9
A
回答
11
JavaFX有用于UI事件的Event Dispatch Thread。所有使用UI的工作都应该发生在这个线程上。非UI计算不应该发生在那里以避免UI中的滞后。
见下面的代码:
public class Indicators extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) {
Pane root = new HBox();
stage.setScene(new Scene(root, 300, 100));
for (int i = 0; i < 10; i++) {
final ProgressIndicator pi = new ProgressIndicator(0);
root.getChildren().add(pi);
// separate non-FX thread
new Thread() {
// runnable for that thread
public void run() {
for (int i = 0; i < 20; i++) {
try {
// imitating work
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException ex) {
ex.printStackTrace();
}
final double progress = i*0.05;
// update ProgressIndicator on FX thread
Platform.runLater(new Runnable() {
public void run() {
pi.setProgress(progress);
}
});
}
}
}.start();
}
stage.show();
}
}
12
这是我如何解决了这个问题:
import java.util.Random;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.concurrent.Worker;
import javafx.concurrent.Worker.State;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.TilePane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class Minimal extends Application {
private TilePane loadPane;
private ProgressIndicator[] indicators = new ProgressIndicator[9];
private Label loading[] = new Label[9];
private Color[] colors = {Color.BLACK,Color.BLUE,Color.CRIMSON,Color.DARKCYAN,Color.FORESTGREEN,Color.GOLD,Color.HOTPINK,Color.INDIGO,Color.KHAKI};
private int counter = 0;
@Override
public void start(Stage primaryStage) throws Exception {
//creating Layout
final Group root = new Group();
Scene scene = new Scene(root, 400, 400);
primaryStage.setScene(scene);
primaryStage.setResizable(false);
StackPane waitingPane = new StackPane();
final ProgressBar progress = new ProgressBar();
Label load = new Label("loading things...");
progress.setTranslateY(-25);
load.setTranslateY(25);
waitingPane.getChildren().addAll(new Rectangle(400,400,Color.WHITE),load,progress);
root.getChildren().add(waitingPane);
//Task for computing the Panels:
Task<Void> task = new Task<Void>() {
@Override
protected Void call() throws Exception {
for (int i = 0; i < 20; i++) {
try {
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException ex) {
ex.printStackTrace();
}
final double prog = i*0.05;
Platform.runLater(new Runnable() {
public void run() {
progress.setProgress(prog);
}
});
}
return null;
}
};
//stateProperty for Task:
task.stateProperty().addListener(new ChangeListener<Worker.State>() {
@Override
public void changed(ObservableValue<? extends State> observable,
State oldValue, Worker.State newState) {
if(newState==Worker.State.SUCCEEDED){
loadPanels(root);
}
}
});
//start Task
new Thread(task).start();
primaryStage.show();
}
private void loadPanels(Group root) {
//change to loadPanel:
root.getChildren().set(0,createLoadPane());
//Service:
final Service<Rectangle> RecBuilder = new Service<Rectangle>() {
@Override protected Task<Rectangle> createTask() {
return new Task<Rectangle>() {
@Override protected Rectangle call() throws InterruptedException {
updateMessage("loading rectangle . . .");
updateProgress(0, 10);
for (int i = 0; i < 10; i++) {
Thread.sleep(100);
}
updateMessage("Finish!");
return new Rectangle((380)/3,(380)/3,colors[counter]);
}
};
}
};
//StateListener
RecBuilder.stateProperty().addListener(new ChangeListener<Worker.State>() {
@Override public void changed(ObservableValue<? extends Worker.State> observableValue,
Worker.State oldState, Worker.State newState) {
switch (newState) {
case SCHEDULED:
break;
case READY:
case RUNNING:
break;
case SUCCEEDED:
Rectangle rec = RecBuilder.valueProperty().getValue();
indicators[counter].progressProperty().unbind();
loading[counter].textProperty().unbind();
loadPane.getChildren().set(counter, rec);
if(counter<8){
counter++;
nextPane(RecBuilder);
}
break;
case CANCELLED:
case FAILED:
loading[counter].textProperty().unbind();
loading[counter].setText("Failed!");
if(counter<8){
counter++;
nextPane(RecBuilder);
}
break;
}
}
});
//begin PanelBuilding:
nextPane(RecBuilder);
}
private void nextPane(Service<Rectangle> recBuilder) {
loading[counter].textProperty().bind(recBuilder.messageProperty());
indicators[counter].visibleProperty().bind(recBuilder.progressProperty().isNotEqualTo(new SimpleDoubleProperty(ProgressBar.INDETERMINATE_PROGRESS)));
recBuilder.restart();
}
private Node createLoadPane() {
loadPane = new TilePane(5,5);
loadPane.setPrefColumns(3);
loadPane.setPadding(new Insets(5));
for(int i=0;i<9;i++){
StackPane waitingPane = new StackPane();
Rectangle background = new Rectangle((380)/3, (380)/3, Color.WHITE);
indicators[i] = new ProgressIndicator();
indicators[i].setPrefSize(50, 50);
indicators[i].setMaxSize(50, 50);
indicators[i].setTranslateY(-25);
indicators[i].setTranslateX(-10);
loading[i] = new Label();
loading[i].setTranslateY(25);
waitingPane.getChildren().addAll(background,indicators[i],loading[i]);
loadPane.getChildren().add(waitingPane);
}
return loadPane;
}
public static void main(String[] args) {
launch(args);
}
}
+0
谢谢。我认为问题是一个任务(更好的单个任务实例)不能运行多次。将任务实例放在一个方法中,让我们通过每个方法调用重新初始化它,这也为我解决了这个问题。尼斯:) – 2015-04-18 13:01:33
相关问题
- 1. 在后台执行任务
- 2. JavaFX中运行的后台任务
- 3. 任务完成后JavaFX执行代码
- 4. 在后台继续执行任务
- 5. 使用NSThread在后台执行任务
- 6. 在asp.net中执行后台任务MVC4
- 7. 如何在后台执行Android任务
- 8. 如何在后台执行任务?
- 9. UWP后台任务未执行
- 10. 防止执行dispatch_after()后台任务
- 11. JavaFX网络后台任务与javafx.concurrent
- 12. JavaFX GUI发布后台任务
- 13. javafx后台任务:在另一个服务中调用服务
- 14. 延迟后在iOS上执行后台任务
- 15. Android服务定期在后台执行任务吗?
- 16. 在rails中立即并行执行的后台任务
- 17. 在后台运行一个任务并继续执行
- 18. Android重复执行任务在后台运行
- 19. JavaFX的后台任务没有运行不止一次
- 20. 后台任务只运行
- 21. 后台任务
- 22. IIS可以托管WCF服务执行后台任务吗?
- 23. 在iOS中的不同线程上执行后台任务
- 24. 在后台执行游戏中的得分任务objective-c
- 25. 如何在Android中定期执行后台任务?
- 26. 什么方法可用于在后台执行任务
- 27. 在后台执行网络和其他耗时任务
- 28. 在iPhone上的应用程序中执行后台任务
- 29. 在Rails控制器执行很短的后台任务
- 30. 如何在后台执行完成的下载任务?
喜谢尔盖......我有一个问题,我可以有几个在应用程序中运行这些线程?谢谢。 – 2015-06-22 15:24:36
@MarcoR,当然,你可以多次运行'new Thread()'。 – 2015-06-22 16:27:18
谢谢谢尔盖,建议在应用程序中有几个Platform.runLater ??。由于这些线程必须更改视图,以检查是否显示对话框。 – 2015-06-22 16:47:59