JavaFX中如何等待用户的操作(同阶段)
How to wait for user's action in JavaFX (in the same stage)
你知道如何在for循环中等待用户输入吗?我不是说 showAndWait()
方法,因为我没有为用户打开一个新的对话阶段。因此,例如,for 循环的每一轮都应等待用户按下按钮,然后再继续下一轮。
怎么可能?非常感谢!
更新:
现在我想到,它可以与 while(buttonNotPressed){}
一起使用,但这是一个好的解决方案吗?我的意思是 while 循环在这种情况下是 运行 疯狂的,直到用户不会按下按钮。或者它是否以某种方式与 wait 方法类似地工作?
把它想象成一个会话:
用户以 handleStart()
开始会话 您给用户 5 个问题,一个接一个。在每次迭代中,用户可以回答即将出现的问题,他可以通过 handleSaveButton()
保存或提交答案。您可以根据需要处理答案,然后继续下一次迭代。关键是,迭代必须停止,直到没有按下保存按钮。
不要那样做。 FX 工具包与任何事件驱动的 GUI 工具包一样,已经实现了一个循环,用于在每次迭代时渲染场景图和处理用户输入。
只需要在按钮上注册一个监听器,然后在按下按钮时做任何你需要做的事情:
button.setOnAction(event -> {
// your code here...
});
如果你想改变动作,只需在每次动作执行时改变一些变量的状态:
private int round = 0 ;
// ...
button.setOnAction(event -> {
if (round < 5) {
System.out.println("Round "+round);
System.out.println("User's input: "+textArea.getText());
round++ ;
}
});
我最近 运行 遇到了一个类似的问题,我希望在用户触发事件之前以一定间隔执行某些操作(如果这就是您的意思)。我找到了 3 种方法来做到这一点:
更新
您应该对自定义可运行对象和计时器使用 stop/cancel 方法,否则当您退出应用程序时线程仍将是 运行。时间轴似乎是自己完成的。
使用定时器:
Timer timer = new Timer();
TimerTask task = new TimerTask() {
@Override
public void run() {
System.out.println("Printed every second.");
}
};
timer.scheduleAtFixedRate(task, 0, 1000);
//timer.cancel();
有时间线:
Timeline tl = new Timeline(new KeyFrame(Duration.millis(1000), e -> {
System.out.println("Timeline");
}));
tl.setCycleCount(Timeline.INDEFINITE);
tl.play();
//tl.stop();
或者制作你自己的可运行程序class:
public class Runner implements Runnable {
private final Thread thread = new Thread(this);
private boolean run;
@Override
public void run() {
while(run) {
try {
System.out.println("Printed from loop");
Thread.sleep(1000);
} catch (InterruptedException e) {
run = false;
}
}
}
public void start() {
run = true;
thread.start();
}
public void stop() {
if(run) {
thread.interrupt();
System.out.print("Thread has stopped.");
}
}
}
然后当有人点击 fx 时。事件将停止的按钮使用 James_D 发布的示例:
Button btn = new Button("Button");
btn.setOnAction(e -> {
timer.cancel();
tl.stop();
runner.stop();
});
在我的例子中,对于 inside for,必须在 class 中创建 2 个索引,使用:
//start method
Timer timer = new Timer();
TimerTask task = new TimerTask()
{
public void run()
{
Platform.runLater(()->{
//... code to run after time, calling the same mehtod, with condition to stop
});
}
};
timer.schedule(task, time);
//end method
必须使用递归方法,根据条件递增索引,导致任务被同时安排,没有等待时间。
我不知道它是否正确,但这是我找到的解决方案。
希望对你有帮助。
替代解决方案W/O暂停:
我正在创建一款游戏,希望用户在游戏开始前选择游戏难度。我没有尝试在中途暂停程序,而是将代码的下一步放在一个单独的方法中,您可以在单击按钮后调用该方法:
private static difficulty;
public static void main(String[] args) {
try {
Application.launch(args);
} catch (UnsupportedOperationException e) {
}
}
public void start(Stage startStage) {
HBox buttons = new HBox();
Button easyButton = new Button("Easy");
Button mediumButton = new Button("Medium");
Button hardButton = new Button("Hard");
buttons.getChildren().addAll(easyButton, mediumButton, hardButton);
buttons.setAlignment(Pos.CENTER);
hbox.getChildren().addAll(buttons);
Scene startScene = new Scene(buttons, 200, 200);
startStage.setScene(startScene);
startStage.show(); // MENU
EventHandler<ActionEvent> playEasy = new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent actionEvent) {
difficulty = 1; // SET DIFFICULTY
startStage.close(); // CLOSE MENU
play(); // RUN GAME ON EASY
}
};
EventHandler<ActionEvent> playMedium = new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent actionEvent) {
difficulty = 2; // SET DIFFICULTY
startStage.close(); // CLOSE MENU
play(); // RUN GAME ON MEDIUM
}
};
EventHandler<ActionEvent> playHard = new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent actionEvent) {
difficulty = 3; // SET DIFFICULTY
startStage.close(); // CLOSE MENU
play(); // RUN GAME ON HARD
}
};
easyButton.setOnAction(playEasy);
mediumButton.setOnAction(playMedium);
hardButton.setOnAction(playHard);
}
public void play() {
// WRITE GAME CODE HERE
}
要解决您的特定问题,您可以将 startStage 传递到播放方法中,然后在那里更新场景...但无论如何我希望这能帮助那些在如何使用按钮方面遇到问题的人! :)
你知道如何在for循环中等待用户输入吗?我不是说 showAndWait()
方法,因为我没有为用户打开一个新的对话阶段。因此,例如,for 循环的每一轮都应等待用户按下按钮,然后再继续下一轮。
怎么可能?非常感谢!
更新:
现在我想到,它可以与 while(buttonNotPressed){}
一起使用,但这是一个好的解决方案吗?我的意思是 while 循环在这种情况下是 运行 疯狂的,直到用户不会按下按钮。或者它是否以某种方式与 wait 方法类似地工作?
把它想象成一个会话:
用户以 handleStart()
开始会话 您给用户 5 个问题,一个接一个。在每次迭代中,用户可以回答即将出现的问题,他可以通过 handleSaveButton()
保存或提交答案。您可以根据需要处理答案,然后继续下一次迭代。关键是,迭代必须停止,直到没有按下保存按钮。
不要那样做。 FX 工具包与任何事件驱动的 GUI 工具包一样,已经实现了一个循环,用于在每次迭代时渲染场景图和处理用户输入。
只需要在按钮上注册一个监听器,然后在按下按钮时做任何你需要做的事情:
button.setOnAction(event -> {
// your code here...
});
如果你想改变动作,只需在每次动作执行时改变一些变量的状态:
private int round = 0 ;
// ...
button.setOnAction(event -> {
if (round < 5) {
System.out.println("Round "+round);
System.out.println("User's input: "+textArea.getText());
round++ ;
}
});
我最近 运行 遇到了一个类似的问题,我希望在用户触发事件之前以一定间隔执行某些操作(如果这就是您的意思)。我找到了 3 种方法来做到这一点:
更新
您应该对自定义可运行对象和计时器使用 stop/cancel 方法,否则当您退出应用程序时线程仍将是 运行。时间轴似乎是自己完成的。
使用定时器:
Timer timer = new Timer();
TimerTask task = new TimerTask() {
@Override
public void run() {
System.out.println("Printed every second.");
}
};
timer.scheduleAtFixedRate(task, 0, 1000);
//timer.cancel();
有时间线:
Timeline tl = new Timeline(new KeyFrame(Duration.millis(1000), e -> {
System.out.println("Timeline");
}));
tl.setCycleCount(Timeline.INDEFINITE);
tl.play();
//tl.stop();
或者制作你自己的可运行程序class:
public class Runner implements Runnable {
private final Thread thread = new Thread(this);
private boolean run;
@Override
public void run() {
while(run) {
try {
System.out.println("Printed from loop");
Thread.sleep(1000);
} catch (InterruptedException e) {
run = false;
}
}
}
public void start() {
run = true;
thread.start();
}
public void stop() {
if(run) {
thread.interrupt();
System.out.print("Thread has stopped.");
}
}
}
然后当有人点击 fx 时。事件将停止的按钮使用 James_D 发布的示例:
Button btn = new Button("Button");
btn.setOnAction(e -> {
timer.cancel();
tl.stop();
runner.stop();
});
在我的例子中,对于 inside for,必须在 class 中创建 2 个索引,使用:
//start method
Timer timer = new Timer();
TimerTask task = new TimerTask()
{
public void run()
{
Platform.runLater(()->{
//... code to run after time, calling the same mehtod, with condition to stop
});
}
};
timer.schedule(task, time);
//end method
必须使用递归方法,根据条件递增索引,导致任务被同时安排,没有等待时间。 我不知道它是否正确,但这是我找到的解决方案。 希望对你有帮助。
替代解决方案W/O暂停:
我正在创建一款游戏,希望用户在游戏开始前选择游戏难度。我没有尝试在中途暂停程序,而是将代码的下一步放在一个单独的方法中,您可以在单击按钮后调用该方法:
private static difficulty;
public static void main(String[] args) {
try {
Application.launch(args);
} catch (UnsupportedOperationException e) {
}
}
public void start(Stage startStage) {
HBox buttons = new HBox();
Button easyButton = new Button("Easy");
Button mediumButton = new Button("Medium");
Button hardButton = new Button("Hard");
buttons.getChildren().addAll(easyButton, mediumButton, hardButton);
buttons.setAlignment(Pos.CENTER);
hbox.getChildren().addAll(buttons);
Scene startScene = new Scene(buttons, 200, 200);
startStage.setScene(startScene);
startStage.show(); // MENU
EventHandler<ActionEvent> playEasy = new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent actionEvent) {
difficulty = 1; // SET DIFFICULTY
startStage.close(); // CLOSE MENU
play(); // RUN GAME ON EASY
}
};
EventHandler<ActionEvent> playMedium = new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent actionEvent) {
difficulty = 2; // SET DIFFICULTY
startStage.close(); // CLOSE MENU
play(); // RUN GAME ON MEDIUM
}
};
EventHandler<ActionEvent> playHard = new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent actionEvent) {
difficulty = 3; // SET DIFFICULTY
startStage.close(); // CLOSE MENU
play(); // RUN GAME ON HARD
}
};
easyButton.setOnAction(playEasy);
mediumButton.setOnAction(playMedium);
hardButton.setOnAction(playHard);
}
public void play() {
// WRITE GAME CODE HERE
}
要解决您的特定问题,您可以将 startStage 传递到播放方法中,然后在那里更新场景...但无论如何我希望这能帮助那些在如何使用按钮方面遇到问题的人! :)