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 传递到播放方法中,然后在那里更新场景...但无论如何我希望这能帮助那些在如何使用按钮方面遇到问题的人! :)