【问题标题】:timer in javaFX using threadjavaFX中使用线程的计时器
【发布时间】:2021-09-25 19:07:25
【问题描述】:

我正在尝试对战海进行编码,在我的一个菜单上,我应该向客户展示他们的地图,并给他们 30 秒的时间来决定他们是否想要一张新地图,或者地图没问题,然后他们就可以开始游戏了。如果他们点击开始游戏按钮,计时器应该停止并且场景会改变。如果他们的时间到了,就像他们点击了开始游戏按钮一样,超时后场景应该会自动改变。如果他们点击新地图按钮,我应该给他们剩余的时间 + 10 来再次决定。我做了一些编码,但我无法完成剩余的+10 部分,而且我不知道如何停止线程。这是我的场景的 FXML 控制器,计时器应该在其中。drawMap 函数在这里并不重要。

public class StandbyMapGuiController implements Initializable {
    @FXML
    private volatile Label timerLabel;
    @FXML
    private GridPane sea;

    private static Stage stage;
    private static int time;
    private GameTimer gameTimer;
    private CountDown countDown;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        drawMap();
        gameTimer = new GameTimer(time,timerLabel , this);
        gameTimer.countDown();
       
    }

    public void updateTimer(int newTime){
        timerLabel.setText(String.valueOf(newTime));
    }
    public void drawMap(){
        for (int i = 0 ; i < 10 ; i++){
            for (int j = 0 ; j < 10 ; j++){
                MapButton btn = new MapButton(i,j);
                btn.setManner(MapButton.COLOR.VIOLET);
                sea.add(btn,j,i);
            }
        }

    }

    public void changeMap(ActionEvent actionEvent) {
        int remaining = Integer.parseInt(timerLabel.getText())+10;
        System.out.println(remaining);
        setTime(remaining);
//restart the page
        Toolbar.getInstance().changeScene(ConfigLoader.readProperty("standbyMapMenuAdd"), actionEvent);
     
    }

    public void startGame() {
        //todo: tell server the gamer is ready
        timerLabel.setText("Time's up");
        try {
            Parent root;
            root = FXMLLoader.load(getClass().getClassLoader().getResource("FXMLs/GameBoard.fxml"));
            Scene scene = new Scene(root);
            stage.setScene(scene);
            stage.show();
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println(e.getMessage());
        }
    }
}

这是我的 GameTimer 类:



public class GameTimer {
    private Timer timer;
    private TimerTask task;
    private int time;
    private volatile Label label;

    public GameTimer(int time, Label label, StandbyMapGuiController controller) {
        this.time = time;
        this.label = label;
        timer = new Timer();
        task = new TimerTask() {
            int counter = time;
            boolean timeOut = false;

public int getCounter() {
                return counter;
            }

            public void setCounter(int counter) {
                this.counter = counter;
            }

            public boolean isTimeOut() {
                return timeOut;
            }

            public void setTimeOut(boolean timeOut) {
                this.timeOut = timeOut;
            }

            @Override
            public void run() {
                Platform.runLater(() -> {
                    if (counter > 0) {
                        label.setText(String.valueOf(counter));
                        counter--;
                    } else {
                        timeOut = true;
                        controller.startGame();
                        timer.cancel();
                    }
                });
            }
        };
    }

    public void countDown() {
        timer.scheduleAtFixedRate(task, 0, 1000);
    }
}

我无法访问 timeOut 和 counter 来设置或获取它们的值。(TimerTask 线程中的 getter 和 setter 不起作用)

【问题讨论】:

    标签: java multithreading javafx timer


    【解决方案1】:

    不要为此使用线程。更好的选择是使用动画。动画是异步的,但在 JavaFX 应用程序线程 上执行。例如,您可以使用PauseTransition

    import javafx.animation.PauseTransition;
    import javafx.application.Application;
    import javafx.application.Platform;
    import javafx.beans.binding.Bindings;
    import javafx.geometry.Insets;
    import javafx.geometry.Pos;
    import javafx.scene.Scene;
    import javafx.scene.control.Alert;
    import javafx.scene.control.Alert.AlertType;
    import javafx.scene.control.Button;
    import javafx.scene.control.Label;
    import javafx.scene.control.ProgressBar;
    import javafx.scene.layout.StackPane;
    import javafx.stage.Stage;
    import javafx.util.Duration;
    
    public class App extends Application {
    
      @Override
      public void start(Stage primaryStage) {
        PauseTransition timer = new PauseTransition(Duration.seconds(30));
        timer.setOnFinished(
            e -> {
              Alert alert = new Alert(AlertType.INFORMATION);
              alert.initOwner(primaryStage);
              alert.setHeaderText(null);
              alert.setContentText("You took too long! Will now exit application.");
              alert.setOnHidden(we -> Platform.exit());
              alert.show();
            });
    
        Button button = new Button("Add ten seconds");
        button.setOnAction(
            e -> {
              e.consume();
              timer.jumpTo(timer.getCurrentTime().subtract(Duration.seconds(10)));
            });
    
        Label timerLabel = new Label();
        timerLabel
            .textProperty()
            .bind(
                Bindings.createStringBinding(
                    () -> {
                      Duration currentTime = timer.getCurrentTime();
                      Duration duration = timer.getDuration();
                      double timeRemaining = duration.subtract(currentTime).toSeconds();
                      return String.format("%04.1f seconds remaining", timeRemaining);
                    },
                    timer.currentTimeProperty(),
                    timer.durationProperty()));
    
        ProgressBar timerProgress = new ProgressBar();
        timerProgress.setMaxWidth(Double.MAX_VALUE);
        timerProgress
            .progressProperty()
            .bind(
                Bindings.createDoubleBinding(
                    () -> {
                      double currentTime = timer.getCurrentTime().toMillis();
                      double duration = timer.getDuration().toMillis();
                      return 1.0 - (currentTime / duration);
                    },
                    timer.currentTimeProperty(),
                    timer.durationProperty()));
    
        StackPane root = new StackPane(button, timerLabel, timerProgress);
        root.setPadding(new Insets(10));
        StackPane.setAlignment(timerLabel, Pos.TOP_LEFT);
        StackPane.setAlignment(timerProgress, Pos.BOTTOM_CENTER);
        primaryStage.setScene(new Scene(root, 600, 400));
        primaryStage.show();
    
        timer.playFromStart();
      }
    }
    

    PauseTransition 有效地从零计数到其持续时间(在本例中为 30 秒)。这就是标签和进度条“反转”时间值以给出剩余时间而不是经过时间的原因。

    注意jumpTo 方法永远不会低于零或高于持续时间。换句话说,如果用户在剩余 25 秒时按下按钮,则剩余时间将增加到 30 秒。如果您希望在这种情况下将剩余时间增加到 35 秒,请更改:

    timer.jumpTo(timer.getCurrentTime().subtract(Duration.seconds(10)));
    

    收件人:

    timer.pause();
    Duration currentTime = timer.getCurrentTime();
    Duration duration = timer.getDuration();
    timer.setDuration(duration.subtract(currentTime).add(Duration.seconds(10)));
    timer.playFromStart();
    

    【讨论】:

    • 谢谢!它救了我的命,进度条很漂亮。
    猜你喜欢
    • 2017-04-18
    • 1970-01-01
    • 1970-01-01
    • 2014-02-21
    • 1970-01-01
    • 1970-01-01
    • 2020-04-30
    相关资源
    最近更新 更多