问题
I've been searching for some time now on how to create multiple tasks and have them run one after the other. Here is the java code:
public class Main extends Application {
DropShadow shadow = new DropShadow();
Button button = new Button("Start");
Task<Integer> task;
Task<Integer> task2;
Label label1 = new Label("Status: NOT STARTED");
ProgressBar bar = new ProgressBar(0);
ProgressIndicator pi = new ProgressIndicator(0);
Thread th = new Thread();
public void start(Stage stage) {
task = new Task<Integer>() {
protected Integer call() throws Exception {
int iterations;
for (iterations = 0; iterations < 1001; iterations++) {
if (isCancelled()) {
updateMessage("Cancelled");
break;
}
updateProgress(iterations, 1001);
updateMessage("Test");
try {
Thread.sleep(10);
} catch (InterruptedException interrupted) {
if (isCancelled()) {
//updateMessage("Cancelled");
break;
}
}
}
return iterations;
}
};
task2 = new Task<Integer>() {
protected Integer call() throws Exception {
int iterations;
for (iterations = 0; iterations < 1001; iterations++) {
if (isCancelled()) {
updateMessage("Cancelled");
break;
}
updateProgress(iterations, 1001);
updateMessage("Test");
try {
Thread.sleep(10);
} catch (InterruptedException interrupted) {
if (isCancelled()) {
//updateMessage("Cancelled");
break;
}
}
}
return iterations;
}
};
task.setOnSucceeded(new EventHandler<WorkerStateEvent>(){
public void handle(WorkerStateEvent arg0) {
label1.setText("Done");
new Thread(task2).start();
}
});
Group root = new Group();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.setTitle("Progress Controls");
final Slider slider = new Slider();
slider.setMin(0);
slider.setMax(50);
bar.progressProperty().bind(task.progressProperty());
pi.progressProperty().bind(task.progressProperty());
label1.textProperty().bind(task.messageProperty());
button.addEventHandler(MouseEvent.MOUSE_PRESSED, new EventHandler<MouseEvent>() {
public void handle(MouseEvent e) {
button.setEffect(shadow);
new Thread(task).start();
}
});
button.addEventHandler(MouseEvent.MOUSE_RELEASED, new EventHandler <MouseEvent>() {
public void handle(MouseEvent arg0) {
button.setEffect(null);
}
});
final HBox hb = new HBox();
hb.setSpacing(5);
hb.setAlignment(Pos.CENTER);
hb.getChildren().addAll(bar, pi, button, label1);
scene.setRoot(hb);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Basically I want to have two progress bars and around 5 tasks in total. One progress bar will be for the current task running and the other one for the overall progress. Once task1 is done, I want it to run task 2 and update the progress bar back to zero while increasing the other progress one. However, once I create a new Thread for the other task nothing in the GUI gets updated.
Thanks in advance.
EDIT: I have fixed the part of the code that starts the second task. However, I have these questions:
How can I create an overall progress bar that gets updated as different tasks get completed?
How can I dynamically reset and update the single progress bar for each individual task once each new task is launched? Do I have to create various ProgressBar objects for this?
回答1:
Your solution works. It's marginal, but I would suggest it's slightly better to have a solution where task1 doesn't know about task2. You can do this by:
- Using an onSucceeded handler to "rebind" the progress bar
- Using a single threaded executor and submitting both tasks to it
For the "overall progress", you could create a DoubleBinding that represents the total progress.
public class Main extends Application {
DropShadow shadow = new DropShadow();
Button button = new Button("Start");
Task<Integer> task;
Task<Integer> task2;
Label label1 = new Label("Status: NOT STARTED");
ProgressBar bar = new ProgressBar(0);
ProgressIndicator pi = new ProgressIndicator(0);
Thread th = new Thread();
public void start(Stage stage) {
task = new Task<Integer>() {
protected Integer call() throws Exception {
int iterations;
for (iterations = 0; iterations < 1001; iterations++) {
if (isCancelled()) {
updateMessage("Cancelled");
break;
}
updateProgress(iterations, 1001);
updateMessage("Test");
try {
Thread.sleep(10);
} catch (InterruptedException interrupted) {
if (isCancelled()) {
//updateMessage("Cancelled");
break;
}
}
}
return iterations;
}
};
task2 = new Task<Integer>() {
protected Integer call() throws Exception {
int iterations;
for (iterations = 0; iterations < 1001; iterations++) {
if (isCancelled()) {
updateMessage("Cancelled");
break;
}
updateProgress(iterations, 1001);
updateMessage("Test");
try {
Thread.sleep(10);
} catch (InterruptedException interrupted) {
if (isCancelled()) {
//updateMessage("Cancelled");
break;
}
}
}
return iterations;
}
};
task.setOnSucceeded(new EventHandler<WorkerStateEvent>(){
public void handle(WorkerStateEvent arg0) {
label1.setText("Done");
bar.progressProperty().unbind();
bar.progressProperty().bind(task2.progressProperty());
}
});
final int numTasks = 2 ;
DoubleBinding totalProgress = Bindings.createDoubleBinding(new Callable<Double>() {
@Override
public Double call() {
return ( Math.max(0, task1.getProgress())
+ Math.max(0, task2.getProgress()) ) / numTasks ;
},
task1.progressProperty(), task2.progressProperty());
pi.progressProperty().bind(totalProgress);
Group root = new Group();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.setTitle("Progress Controls");
final Slider slider = new Slider();
slider.setMin(0);
slider.setMax(50);
bar.progressProperty().bind(task.progressProperty());
// pi.progressProperty().bind(task.progressProperty());
label1.textProperty().bind(task.messageProperty());
final ExecutorService exec = Executors.newSingleThreadExecutor();
button.addEventHandler(MouseEvent.MOUSE_PRESSED, new EventHandler<MouseEvent>() {
public void handle(MouseEvent e) {
button.setEffect(shadow);
exec.submit(task);
exec.submit(task2);
}
});
button.addEventHandler(MouseEvent.MOUSE_RELEASED, new EventHandler <MouseEvent>() {
public void handle(MouseEvent arg0) {
button.setEffect(null);
}
});
final HBox hb = new HBox();
hb.setSpacing(5);
hb.setAlignment(Pos.CENTER);
hb.getChildren().addAll(bar, pi, button, label1);
scene.setRoot(hb);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
回答2:
I found my own solution but not sure if it's the best implementation.
Basically I just used the succeed method from Task and unbinded the progressbar and then binded it again with the new task.
task = new Task<Integer>() {
protected Integer call() throws Exception {
int iterations;
for (iterations = 0; iterations < 1001; iterations++) {
if (isCancelled()) {
updateMessage("Cancelled");
break;
}
updateProgress(iterations, 1001);
updateMessage("Test");
try {
Thread.sleep(10);
} catch (InterruptedException interrupted) {
if (isCancelled()) {
//updateMessage("Cancelled");
break;
}
}
}
return iterations;
}
@Override
protected void succeeded() {
super.succeeded();
updateMessage("Done");
bar.progressProperty().unbind();
bar.progressProperty().bind(task2.progressProperty());
new Thread(task2).start();
}
};
That solved the issue on how to update the progress bar for each individual task
来源:https://stackoverflow.com/questions/22971222/multiple-tasks-javafx