java - 如何根据单独类的进度更新 JavaFX 进度指示器?
问题描述
我有一个由 4 个类组成的程序:
1) GUI.java - 包含 JavaFX 进度指示器 GUI 的程序
2) mainRun.java - 运行 task1.java 和 task2.java 的“主”类。在实际程序中,mainRun.java 将负责整合task1.java 和task2.java 中的一些信息,因此需要这个类。
3) task1.java - 将在 task2.java 之前运行的程序
4)task2.java - 将在 task1.java 之后运行的程序
我想根据 task1.java 和 task2.java 中的 updateProgress(X,Y) 函数更新 GUI.java 的进度指示器。
但是,mainRun.java 将是调用 task1.java 和之后的 task2.java 的程序。因此,GUI.java 的进度指示器将仅根据从 mainRun.java 调用的 updateProgress(X,Y) 函数更新其进度。
每当在 task1.java 和 task2.java 中运行 updateProgress(X,Y) 函数(可能绕过 mainRun.java?)时,如何更新 GUI.java 的进度指示器?
否则,有没有一种方法可以主动通知 mainRun.java 来自 task1.java 和 task2.java 的 updateProgress(X,Y) 并在收到通知时更新 GUI.java 的进度指示器?
这是我正在描述的问题的模拟伪示例:
图形用户界面.java
public class GUI extends Application {
private mainRun mainTask;
@Override
public void start(Stage primaryStage) {
final ProgressIndicator progressIndicator = new ProgressIndicator(0);
final Button startButton = new Button("Start");
// Start Button.
startButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
mainTask = new mainRun();
progressIndicator.progressProperty().unbind();
progressIndicator.setProgress(0);
progressIndicator.progressProperty().unbind();
progressIndicator.progressProperty().bind(mainTask.progressProperty());
new Thread(mainTask).start();
}
});
... JavaFX stage code ...
}
}
mainRun.java
public class CopyTask extends Task<String> {
@Override
protected String call() throws Exception {
/** Update GUI.java's progress bar based on t1 here **/
task1 t1 = new task1();
ProgressIndicator progress = new ProgressIndicator(0);
progress.progressProperty().unbind();
progress.setProgress(0);
progress.progressProperty().bind(t1.progressProperty());
new Thread(t1).start();
t1.addEventHandler(WorkerStateEvent.WORKER_STATE_SUCCEEDED, //
new EventHandler<WorkerStateEvent>() {
@Override
public void handle(WorkerStateEvent t) {
/** Continue updating GUI.java's progress bar based on t2 here **/
task2 t2 = new task2();
progress.progressProperty().unbind();
progress.progressProperty().bind(t2.progressProperty());
new Thread(t2).start();
}
});
return "Done";
}
}
任务1.java
public class task1 extends Task<String> {
protected String call() throws Exception {
for (int i =0; i<1000; i++) {
this.updateProgress(i,2000); // currently updates mainRun.java progress bar NOT GUI.java
}
return "";
}
}
任务2.java
public class task2 extends Task<String> {
protected String call() throws Exception {
for (int i =1000; i<2000; i++) {
this.updateProgress(i,2000); // currently updates mainRun.java progress bar NOT GUI.java
}
return "";
}
更新: 感谢用户 c0der 找到了解决方案:
progressIndicator.progressProperty().bind(copyTask.t1.progressProperty().add(copyTask.t2.progressProperty()));**
更新: 发现这个线程通过一个可靠的例子完美地解决了所有问题。
解决方案
您可以通过将进度条的进度属性绑定到两个进度属性来做到这一点:
import java.util.concurrent.TimeUnit;
import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.geometry.Insets;
import javafx.geometry.Orientation;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class TwoLongProcessWithOneProgressBar extends Application {
@Override
public void start(Stage stage) throws InterruptedException {
BorderPane mainPane = new BorderPane();
FlowPane topPane = new FlowPane(Orientation.HORIZONTAL, 5.,5.);
topPane.setPadding(new Insets(20.));
Panel panel = new Panel();
BorderPane.setAlignment(panel, Pos.CENTER);
Button button = new Button("Start");
button.setDefaultButton(true);
button.setOnAction(e -> {
panel.runLlongTask();
button.setDisable(true);
});
topPane.getChildren().add(button);
mainPane.setTop(topPane);
mainPane.setCenter(panel);
mainPane.setBottom(panel.getBar());
Scene scene = new Scene(mainPane, Color.WHITE);
stage.setScene(scene);
stage.centerOnScreen();
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
class Panel extends HBox{
private final ProgressBar bar;
Panel(){
setPrefSize(150,50);
bar = new ProgressBar();
bar.prefWidthProperty().bind(widthProperty());
}
void runLlongTask() {
Task task1 = new Task1();
Thread th1 = new Thread(task1);
th1.setDaemon(true);
Task task2 = new Task2();
Thread th2 = new Thread(task2);
th2.setDaemon(true);
//bind progress bar to both task progress property
bar.progressProperty().bind(task1.progressProperty().add(task2.progressProperty()));
th1.start();
th2.start();
}
ProgressBar getBar() { return bar; }
}
class Task1 extends Task<Void>{
@Override
protected Void call() throws Exception {
for (int i =0; i<1000; i++) {
TimeUnit.MILLISECONDS.sleep(100);
updateProgress(i,2000);
}
return null;
}
}
class Task2 extends Task<Void>{
@Override
protected Void call() throws Exception {
for (int i =0; i<1000; i++) {
TimeUnit.MILLISECONDS.sleep(100);
updateProgress(i,2000);
}
return null;
}
}
推荐阅读
- javascript - 如何使用 Javascript 从 XPATH 结果中查找重复行?
- java - 从服务器读取 pdf 写入新的 pdf 文件
- c# - HoverRace 教程脚本中的错误
- chef-infra - 在数据包更新时自动运行 chef-client
- php - 如何在不创建新表或 th 的情况下获取 1 个表中的所有产品名称
- r - 是否可以通过 RPostgresql 运行 Postgres 反斜杠命令?
- c# - 为什么我的查询字符串参数被 url 解码两次?
- php - Web Scraper - PHP - 简单的 html dom
- javascript - 节点作为强制布局中的列表(在地图上)
- git - 有没有办法在 Git 中不使用 Commit 或 Stash 来保存我当前的更改?