如何停止 JavaFX 线程并使用警告框等待用户输入
How to stop a JavaFX thread and wait for user input with an Alert Box
我创建了一个 JavaFX 应用程序,我希望它具有以下功能:
开始 运行 - 当 运行 每 2 秒将 appendText() 添加到 JavaFX TextArea 时,然后随机停止一切并显示 Alert.Error.
这真的很基础。我在 Stack Overflow 上搜索了一下,但找不到任何东西。如果此问题已得到解答,请指点我。
为了更好地解释我的问题,这里有一些代码和一些屏幕截图。
package com.example.threadstestingplatformrunlater;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.TextArea;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.io.IOException;
import static java.lang.Thread.sleep;
public class HelloApplication extends Application {
private static int counter;
private TextArea textArea;
@Override public void start(Stage stage) throws IOException {
VBox vBox = new VBox();
textArea = new TextArea();
vBox.getChildren().add(textArea);
Scene scene = new Scene(vBox);
vBox.setStyle(ThemeClass.DARK_THEME);
stage.setTitle("Hello!");
stage.setScene(scene);
stage.show();
System.out.println("Thread Name: " + Thread.currentThread().getName() );
Thread thread = new Thread(this::run);
thread.start();
}
private void functionContainingRunLater() throws InterruptedException {
System.out.println("Thread Name: " + Thread.currentThread().getName() );
continuouslyWrite(textArea);
}
public static void continuouslyWrite(TextArea textArea) throws InterruptedException {
for (int i = 0; i < 20; i++) {
if(i == 10) {
Platform.runLater(()-> {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.show();
});
}
System.out.println(counter);
textArea.appendText(Thread.currentThread().getName() + ": " + counter+ "\n");
counter++;
if (counter > 500) {
break;
}
sleep(200);
}
}
public static void main(String[] args) {
launch();
}
private void run() {
try {
functionContainingRunLater();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
此代码运行并在运行时在 TextArea 上写入行。实时。到目前为止我遇到了很多问题 - 或多或少,它只会在一切都完成后才写入。
现在我想在 i == 10
时停止它,但我只显示 Alert.Message 然后它一直持续到最后。我想让代码暂停。我怎样才能做到这一点?
我试过:
public static void continuouslyWrite(TextArea textArea) throws InterruptedException {
for (int i = 0; i < 20; i++) {
if(i == 10) {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.show();
}
System.out.println(counter);
textArea.appendText(Thread.currentThread().getName() + ": " + counter+ "\n");
counter++;
if (counter > 500) {
break;
}
sleep(200);
}
}
但在这种情况下,我得到了不在 JavaFX 线程上的错误。
Exception in thread "Thread-3" java.lang.IllegalStateException: Not on
FX application thread; currentThread = Thread-3
你能帮我理解我怎样才能做到这一点吗?我想做的事有可能吗?不知怎的,我无法理解它。
如评论中所述,以及本网站上的许多问题和 API 文档中的显着位置,您 不得 更新 UI 来自后台线程。 TextArea
不会对此进行检查并抛出异常,但您仍然违反了 JavaFX 的线程规则。
仅仅因为您的代码恰好可以在您的特定系统和您正在使用的特定 JavaFX/JVM 版本上运行并不意味着您的代码没有损坏。
一般来说,对于 运行 定期更新 UI 的内容,您应该使用动画 API。参见 JavaFX periodic background task, in particular this answer。在您的情况下,这有点棘手,因为您不能直接从动画事件处理程序调用 showAndWait()
。
所以你可以这样做:
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.TextArea;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;
import java.io.IOException;
public class HelloApplication extends Application {
private int counter;
private TextArea textArea;
@Override public void start(Stage stage) throws IOException {
VBox vBox = new VBox();
textArea = new TextArea();
vBox.getChildren().add(textArea);
Scene scene = new Scene(vBox);
stage.setTitle("Hello!");
stage.setScene(scene);
stage.show();
System.out.println("Thread Name: " + Thread.currentThread().getName() );
Timeline timeline = new Timeline();
KeyFrame keyFrame = new KeyFrame(Duration.seconds(0.2), event -> {
textArea.appendText(Thread.currentThread().getName() + ": " + counter+ "\n");
counter++;
if (counter == 10) {
timeline.pause();
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
Platform.runLater(() -> {
alert.showAndWait();
timeline.play();
});
}
});
timeline.getKeyFrames().add(keyFrame);
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();
}
public static void main(String[] args) {
launch();
}
}
如果您真的 want/need 使用线程(老实说我不认为您会这样做),您可以使用 JavaFX2: Can I pause a background Task / Service?:
中所示的技术
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.TextArea;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class HelloApplication extends Application {
private int counter;
private TextArea textArea;
@Override public void start(Stage stage) throws IOException {
VBox vBox = new VBox();
textArea = new TextArea();
vBox.getChildren().add(textArea);
Scene scene = new Scene(vBox);
stage.setTitle("Hello!");
stage.setScene(scene);
stage.show();
System.out.println("Thread Name: " + Thread.currentThread().getName() );
Thread thread = new Thread(() -> {
try {
for (int i = 0; i < 20; i++) {
if(i == 10) {
FutureTask<Void> interrupt = new FutureTask<>(() -> {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.showAndWait();
return null ;
});
Platform.runLater(interrupt);
interrupt.get();
}
System.out.println(counter);
Platform.runLater(() ->
textArea.appendText(Thread.currentThread().getName() + ": " + counter+ "\n"));
counter++;
if (counter > 500) {
break;
}
Thread.sleep(200);
}
} catch (InterruptedException exc) {
Thread.currentThread().interrupt();
} catch (ExecutionException exc) {
exc.printStackTrace();
}
});
thread.start();
}
public static void main(String[] args) {
launch();
}
}
我创建了一个 JavaFX 应用程序,我希望它具有以下功能:
开始 运行 - 当 运行 每 2 秒将 appendText() 添加到 JavaFX TextArea 时,然后随机停止一切并显示 Alert.Error.
这真的很基础。我在 Stack Overflow 上搜索了一下,但找不到任何东西。如果此问题已得到解答,请指点我。
为了更好地解释我的问题,这里有一些代码和一些屏幕截图。
package com.example.threadstestingplatformrunlater;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.TextArea;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.io.IOException;
import static java.lang.Thread.sleep;
public class HelloApplication extends Application {
private static int counter;
private TextArea textArea;
@Override public void start(Stage stage) throws IOException {
VBox vBox = new VBox();
textArea = new TextArea();
vBox.getChildren().add(textArea);
Scene scene = new Scene(vBox);
vBox.setStyle(ThemeClass.DARK_THEME);
stage.setTitle("Hello!");
stage.setScene(scene);
stage.show();
System.out.println("Thread Name: " + Thread.currentThread().getName() );
Thread thread = new Thread(this::run);
thread.start();
}
private void functionContainingRunLater() throws InterruptedException {
System.out.println("Thread Name: " + Thread.currentThread().getName() );
continuouslyWrite(textArea);
}
public static void continuouslyWrite(TextArea textArea) throws InterruptedException {
for (int i = 0; i < 20; i++) {
if(i == 10) {
Platform.runLater(()-> {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.show();
});
}
System.out.println(counter);
textArea.appendText(Thread.currentThread().getName() + ": " + counter+ "\n");
counter++;
if (counter > 500) {
break;
}
sleep(200);
}
}
public static void main(String[] args) {
launch();
}
private void run() {
try {
functionContainingRunLater();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
此代码运行并在运行时在 TextArea 上写入行。实时。到目前为止我遇到了很多问题 - 或多或少,它只会在一切都完成后才写入。
现在我想在 i == 10
时停止它,但我只显示 Alert.Message 然后它一直持续到最后。我想让代码暂停。我怎样才能做到这一点?
我试过:
public static void continuouslyWrite(TextArea textArea) throws InterruptedException {
for (int i = 0; i < 20; i++) {
if(i == 10) {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.show();
}
System.out.println(counter);
textArea.appendText(Thread.currentThread().getName() + ": " + counter+ "\n");
counter++;
if (counter > 500) {
break;
}
sleep(200);
}
}
但在这种情况下,我得到了不在 JavaFX 线程上的错误。
Exception in thread "Thread-3" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-3
你能帮我理解我怎样才能做到这一点吗?我想做的事有可能吗?不知怎的,我无法理解它。
如评论中所述,以及本网站上的许多问题和 API 文档中的显着位置,您 不得 更新 UI 来自后台线程。 TextArea
不会对此进行检查并抛出异常,但您仍然违反了 JavaFX 的线程规则。
仅仅因为您的代码恰好可以在您的特定系统和您正在使用的特定 JavaFX/JVM 版本上运行并不意味着您的代码没有损坏。
一般来说,对于 运行 定期更新 UI 的内容,您应该使用动画 API。参见 JavaFX periodic background task, in particular this answer。在您的情况下,这有点棘手,因为您不能直接从动画事件处理程序调用 showAndWait()
。
所以你可以这样做:
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.TextArea;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;
import java.io.IOException;
public class HelloApplication extends Application {
private int counter;
private TextArea textArea;
@Override public void start(Stage stage) throws IOException {
VBox vBox = new VBox();
textArea = new TextArea();
vBox.getChildren().add(textArea);
Scene scene = new Scene(vBox);
stage.setTitle("Hello!");
stage.setScene(scene);
stage.show();
System.out.println("Thread Name: " + Thread.currentThread().getName() );
Timeline timeline = new Timeline();
KeyFrame keyFrame = new KeyFrame(Duration.seconds(0.2), event -> {
textArea.appendText(Thread.currentThread().getName() + ": " + counter+ "\n");
counter++;
if (counter == 10) {
timeline.pause();
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
Platform.runLater(() -> {
alert.showAndWait();
timeline.play();
});
}
});
timeline.getKeyFrames().add(keyFrame);
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();
}
public static void main(String[] args) {
launch();
}
}
如果您真的 want/need 使用线程(老实说我不认为您会这样做),您可以使用 JavaFX2: Can I pause a background Task / Service?:
中所示的技术import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.TextArea;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class HelloApplication extends Application {
private int counter;
private TextArea textArea;
@Override public void start(Stage stage) throws IOException {
VBox vBox = new VBox();
textArea = new TextArea();
vBox.getChildren().add(textArea);
Scene scene = new Scene(vBox);
stage.setTitle("Hello!");
stage.setScene(scene);
stage.show();
System.out.println("Thread Name: " + Thread.currentThread().getName() );
Thread thread = new Thread(() -> {
try {
for (int i = 0; i < 20; i++) {
if(i == 10) {
FutureTask<Void> interrupt = new FutureTask<>(() -> {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.showAndWait();
return null ;
});
Platform.runLater(interrupt);
interrupt.get();
}
System.out.println(counter);
Platform.runLater(() ->
textArea.appendText(Thread.currentThread().getName() + ": " + counter+ "\n"));
counter++;
if (counter > 500) {
break;
}
Thread.sleep(200);
}
} catch (InterruptedException exc) {
Thread.currentThread().interrupt();
} catch (ExecutionException exc) {
exc.printStackTrace();
}
});
thread.start();
}
public static void main(String[] args) {
launch();
}
}