我正在尝试创建一个加载程序对话框,用户可以在其中知道程序正在加载所请求的内容并且程序正在按预期运行。
但因此,我需要
join()
解析器线程,然后继续主线程,这会使对话框空白。
ParserTask.java
public class ParserTask extends Task<Void>{
@Override
protected Void call() throws Exception {
for(int i=0;i<10;i++){
//parse stuff
Thread.sleep(1000);
updateProgress(i,9);
updateMessage("foo no:"+ i);
}
updateMessage("done");
return null;
}
}
Main.java
import javafx.application.Application;
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.GridPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage stage) {
Group root = new Group();
Scene scene = new Scene(root, 300, 150);
stage.setScene(scene);
stage.setTitle("Progress Controls");
Button btn = new Button("call the thread");
btn.setOnAction(new EventHandler<ActionEvent>(){
@Override
public void handle(ActionEvent arg0) {
threadDialog();
}
});
VBox vb = new VBox();
vb.getChildren().addAll(btn);
scene.setRoot(vb);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
private void threadDialog() {
Stage stageDiag = new Stage();
ParserTask pTask = new ParserTask();
final Label loadingLabel = new Label("");
loadingLabel.textProperty().bind(pTask.messageProperty());
final ProgressBar pbar = new ProgressBar();
pbar.setProgress(0);
pbar.setPrefHeight(20);
pbar.setPrefWidth(450);
pbar.progressProperty().bind(pTask.progressProperty());
GridPane grid = new GridPane();
grid.setHgap(14.0);
grid.add(loadingLabel, 0, 0);
grid.add(pbar, 1, 1);
Scene sceneDiag = new Scene(grid);
stageDiag.setScene(sceneDiag);
stageDiag.setTitle("Foo thread is loading");
stageDiag.show();
Thread parser = new Thread(pTask);
parser.start();
try {
parser.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
如果,我评论/删除此代码:
try {
parser.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
然后,我可以看到线程按预期加载,否则,我只能看到处于最终状态的空白屏幕(最后一条消息和完整的进度条)。
while(!loadingLabel.getText().contains("one")){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
甚至
while(parser.isAlive());
也没有成功。
我的问题是:如何等待我的线程并保持 UI 正常工作?
永远不应该阻塞 UI 线程。
后台处理的典型模式如下所示:
Platform.runLater()
调用执行此操作的代码(以及从后台线程与 UI 交互的任何其他代码)简化示例:
btn.setOnAction(new EventHandler<ActionEvent>(){
@Override
public void handle(ActionEvent arg0) {
// 1
setBackgroundProcessing(true);
// 2
new Thread() {
public void run() {
doProcessing();
// 3
Platform.runLater(new Runnable() {
public void run() {
displayResults();
setBackgroundProcessing(false);
}
});
}
}.start();
}
});
上面的代码不是很优雅,您可能需要使用线程池和/或
ListenableFuture
使其看起来更好。
使用 Platform.runLater()
有两个基本使用规则:
第二个特别重要,因为 JavaFX 正在平衡您的 Runnable 与其自己的工作负载。如果您使用密集的 Runnables 淹没 Platform.runLater(),界面可能会变得无响应。
可以看【参考链接】[1]