JavaFX:在 TextArea 中显示文本,每行之间有延迟
JavaFX: Display text in TextArea with delay in between each line
我正在尝试在 TextArea 中显示文本,每个句子之间都有延迟,就像您正在进行对话一样。
我尝试使用睡眠功能,但这不起作用,因为文本仅在所有方法停止时显示 运行ning。
执行此操作的有效方法是什么:
(伪代码)
textArea.appendText("Goodday sir, how are you doing?");
(0.5 second delay);
textArea.appendText("I'm fine thanks");
(1 second delay);
textArea.appendText("What can I do for you?");
getPlayerInput();
textArea.appendText("Sure, I'll take care of it.");
澄清我要做什么:
在 textArea 中显示文本,中间有延迟,并且能够 运行 在中间发挥作用。
您可以使用时间轴的 onFinished 在 JavaFX 中进行延迟操作
试试下面的代码
package application;
import java.util.ArrayList;
import java.util.Iterator;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Main extends Application {
Timeline delay = new Timeline();
TextArea textArea = new TextArea();
boolean waitForInput = false;
Msg current;
@Override
public void start(Stage primaryStage) {
StackPane root = new StackPane();
root.getChildren().add(textArea);
Scene scene = new Scene(root, 500, 500);
ArrayList<Msg> msgs = new ArrayList<Msg>();
msgs.add(new Msg("Goodday sir, how are you doing?\n", Duration.seconds(1), false));
msgs.add(new Msg("i'm fine thanks!\n", Duration.seconds(2), false));
msgs.add(new Msg("What can I do for you?\n", Duration.seconds(0.1), true));
msgs.add(new Msg("Sure, I'll take care of it.\n", Duration.seconds(1), false));
msgs.add(new Msg("....", Duration.seconds(0.5), false));
msgs.add(new Msg("are you sure it's the only thing you need?\n", Duration.seconds(0.1), true));
msgs.add(new Msg("alright bye", Duration.seconds(0), true));
Iterator<Msg> it = msgs.iterator();
delay.getKeyFrames().setAll(new KeyFrame(Duration.seconds(0)));
delay.setOnFinished(e -> {
if (it.hasNext()) {
current = it.next();
delay.getKeyFrames().setAll(new KeyFrame(current.getDuration()));
delay.playFromStart();
textArea.appendText(current.getContent());
if (current.requiresInput()) {
waitForInput = true;
delay.pause();
}
}
});
delay.playFromStart();
primaryStage.setScene(scene);
primaryStage.show();
scene.addEventFilter(KeyEvent.KEY_PRESSED, e ->
{
if (waitForInput && e.getCode().equals(KeyCode.ENTER)) {
delay.play();
waitForInput = false;
}
});
scene.addEventFilter(KeyEvent.KEY_TYPED, e -> {
if (!waitForInput) {
e.consume();
}
});
}
public static void main(String[] args) {
launch(args);
}
class Msg {
private boolean requireInput;
private String content;
private Duration duration;
public Msg(String c, Duration d, boolean b) {
content = c;
duration = d;
requireInput = b;
}
public String getContent() {
return content;
}
public Duration getDuration() {
return duration;
}
public boolean requiresInput() {
return requireInput;
}
}
}
作为另一个答案中时间轴的变体,您可以为要显示的每条消息创建不同的 KeyFrame
。这避免了 "nested timelines" 的情况,我认为如果您有超过两到三个消息要一个接一个地显示,这将变得难以管理。
这是一个使用这个想法的 SSCCE:
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Conversation extends Application {
private TextArea console ;
private TextField input ;
private BooleanProperty readyForInput ;
private Timeline createTimeline(String[] messages) {
Timeline timeline = new Timeline();
Duration delayBetweenMessages = Duration.seconds(1);
Duration frame = delayBetweenMessages ;
for (String msg : messages) {
timeline.getKeyFrames().add(new KeyFrame(frame, e -> console.appendText(msg+"\n")));
frame = frame.add(delayBetweenMessages);
}
timeline.statusProperty().addListener((obs, oldStatus, newStatus) -> {
readyForInput.set(newStatus != Animation.Status.RUNNING);
if (newStatus != Animation.Status.RUNNING) {
input.requestFocus();
}
});
return timeline ;
}
@Override
public void start(Stage primaryStage) {
readyForInput = new SimpleBooleanProperty(false);
console = new TextArea();
console.setEditable(false);
input = new TextField();
input.disableProperty().bind(readyForInput.not());
input.setOnAction(e -> {
String inputText = input.getText();
console.appendText("> "+inputText+"\n");
input.clear();
createTimeline(getMessages(inputText)).play();
});
BorderPane root = new BorderPane(console, input, null, null, null) ;
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
createTimeline(getMessages(null)).play();
}
private String[] getMessages(String input) {
if (input == null || input.isEmpty()) {
return new String[] {
"Goodday sir, how are you doing?",
"I'm fine thanks",
"What can I do for you?"
};
} else {
// AI logic here...
return new String[] { "Sure, I'll take care of it." };
}
}
public static void main(String[] args) {
launch(args);
}
}
我正在尝试在 TextArea 中显示文本,每个句子之间都有延迟,就像您正在进行对话一样。 我尝试使用睡眠功能,但这不起作用,因为文本仅在所有方法停止时显示 运行ning。 执行此操作的有效方法是什么:
(伪代码)
textArea.appendText("Goodday sir, how are you doing?");
(0.5 second delay);
textArea.appendText("I'm fine thanks");
(1 second delay);
textArea.appendText("What can I do for you?");
getPlayerInput();
textArea.appendText("Sure, I'll take care of it.");
澄清我要做什么: 在 textArea 中显示文本,中间有延迟,并且能够 运行 在中间发挥作用。
您可以使用时间轴的 onFinished 在 JavaFX 中进行延迟操作
试试下面的代码
package application;
import java.util.ArrayList;
import java.util.Iterator;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Main extends Application {
Timeline delay = new Timeline();
TextArea textArea = new TextArea();
boolean waitForInput = false;
Msg current;
@Override
public void start(Stage primaryStage) {
StackPane root = new StackPane();
root.getChildren().add(textArea);
Scene scene = new Scene(root, 500, 500);
ArrayList<Msg> msgs = new ArrayList<Msg>();
msgs.add(new Msg("Goodday sir, how are you doing?\n", Duration.seconds(1), false));
msgs.add(new Msg("i'm fine thanks!\n", Duration.seconds(2), false));
msgs.add(new Msg("What can I do for you?\n", Duration.seconds(0.1), true));
msgs.add(new Msg("Sure, I'll take care of it.\n", Duration.seconds(1), false));
msgs.add(new Msg("....", Duration.seconds(0.5), false));
msgs.add(new Msg("are you sure it's the only thing you need?\n", Duration.seconds(0.1), true));
msgs.add(new Msg("alright bye", Duration.seconds(0), true));
Iterator<Msg> it = msgs.iterator();
delay.getKeyFrames().setAll(new KeyFrame(Duration.seconds(0)));
delay.setOnFinished(e -> {
if (it.hasNext()) {
current = it.next();
delay.getKeyFrames().setAll(new KeyFrame(current.getDuration()));
delay.playFromStart();
textArea.appendText(current.getContent());
if (current.requiresInput()) {
waitForInput = true;
delay.pause();
}
}
});
delay.playFromStart();
primaryStage.setScene(scene);
primaryStage.show();
scene.addEventFilter(KeyEvent.KEY_PRESSED, e ->
{
if (waitForInput && e.getCode().equals(KeyCode.ENTER)) {
delay.play();
waitForInput = false;
}
});
scene.addEventFilter(KeyEvent.KEY_TYPED, e -> {
if (!waitForInput) {
e.consume();
}
});
}
public static void main(String[] args) {
launch(args);
}
class Msg {
private boolean requireInput;
private String content;
private Duration duration;
public Msg(String c, Duration d, boolean b) {
content = c;
duration = d;
requireInput = b;
}
public String getContent() {
return content;
}
public Duration getDuration() {
return duration;
}
public boolean requiresInput() {
return requireInput;
}
}
}
作为另一个答案中时间轴的变体,您可以为要显示的每条消息创建不同的 KeyFrame
。这避免了 "nested timelines" 的情况,我认为如果您有超过两到三个消息要一个接一个地显示,这将变得难以管理。
这是一个使用这个想法的 SSCCE:
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Conversation extends Application {
private TextArea console ;
private TextField input ;
private BooleanProperty readyForInput ;
private Timeline createTimeline(String[] messages) {
Timeline timeline = new Timeline();
Duration delayBetweenMessages = Duration.seconds(1);
Duration frame = delayBetweenMessages ;
for (String msg : messages) {
timeline.getKeyFrames().add(new KeyFrame(frame, e -> console.appendText(msg+"\n")));
frame = frame.add(delayBetweenMessages);
}
timeline.statusProperty().addListener((obs, oldStatus, newStatus) -> {
readyForInput.set(newStatus != Animation.Status.RUNNING);
if (newStatus != Animation.Status.RUNNING) {
input.requestFocus();
}
});
return timeline ;
}
@Override
public void start(Stage primaryStage) {
readyForInput = new SimpleBooleanProperty(false);
console = new TextArea();
console.setEditable(false);
input = new TextField();
input.disableProperty().bind(readyForInput.not());
input.setOnAction(e -> {
String inputText = input.getText();
console.appendText("> "+inputText+"\n");
input.clear();
createTimeline(getMessages(inputText)).play();
});
BorderPane root = new BorderPane(console, input, null, null, null) ;
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
createTimeline(getMessages(null)).play();
}
private String[] getMessages(String input) {
if (input == null || input.isEmpty()) {
return new String[] {
"Goodday sir, how are you doing?",
"I'm fine thanks",
"What can I do for you?"
};
} else {
// AI logic here...
return new String[] { "Sure, I'll take care of it." };
}
}
public static void main(String[] args) {
launch(args);
}
}