#java #multithreading #javafx #javafx-2 #task
#java #многопоточность #javafx #javafx-2 #задача
Вопрос:
Я пытаюсь создать диалоговое окно загрузки, в котором пользователь может знать, что программа загружает то, что было запрошено, и что программа работает должным образом.
Но в таком случае мне нужно 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());
безуспешно.
Мой вопрос: как я могу дождаться своего потока и сохранить пользовательский интерфейс в рабочем состоянии?
Комментарии:
1. Примерно в миллионный раз повторяю, никогда не ждите, что будет в потоках событий GUI-hanler.
Ответ №1:
Вы никогда не должны блокировать поток пользовательского интерфейса.
Типичный шаблон для фоновой обработки выглядит следующим образом:
- Измените пользовательский интерфейс, чтобы указать, что выполняется фоновая обработка (показать индикатор выполнения, отключить кнопки и т.д.)
- Запустите фоновый поток
- В фоновом потоке после завершения обработки измените пользовательский интерфейс обратно и отобразите результаты обработки. Код, который это делает, должен вызываться с помощью
Platform.runLater()
(а также любой другой код, который взаимодействует с пользовательским интерфейсом из фоновых потоков)
Упрощенный пример:
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
ы, чтобы он выглядел лучше.