new Thread, application still running after Stage-close

前端 未结 2 495
梦毁少年i
梦毁少年i 2021-01-15 01:41

So I followed this tutorial: https://www.youtube.com/watch?v=gyyj57O0FVI

and I made exactly the same code in javafx8.

public class CountdownControll         


        
相关标签:
2条回答
  • 2021-01-15 02:12

    With ScheduledExecutorService as far as I am concerned You cant easly set it as deamon and I don't want to play with stage.setOnCloseRequest(closeEvent -> {});

    With AnimationTimer I cant do something like Thread.sleep(100) beetween iteration like you suggested because "AnimationTimer runs on the JavaFX thread."

    ScheduledService is just quite difficult for me to understand right now...

    so, as I was reading and reading about it I came to conclusion that maybe this simple option will be the best:

    public class CountdownController implements Initializable{
    
    @FXML
    private Label labTime;
    @FXML
    private Button buttSTOP;
    
    @Override
    public void initialize(URL location, ResourceBundle resources) {
         Timer timer = new Timer(true); //set it as a deamon
         timer.schedule(new MyTimer(), 0, 1000);
    }
    
    
    public class MyTimer extends TimerTask{
        @Override
        public void run() {
            Calendar calendar = new GregorianCalendar();
            int hour = calendar.get(Calendar.HOUR);
            int minute = calendar.get(Calendar.MINUTE);
            int second = calendar.get(Calendar.SECOND);
            String time = hour + ":" + minute + ":" + second;
    
            Platform.runLater(() -> {
                labTime.setText(time);
            });
    
        }
    }
    

    Thanks James_D and ItachiUchiha. It works, let me know if I'am something missing!

    EDIT: I also include code for Counting down the time, as it was my initial aim, maybe someone will find it usefull as well:

    public class CountdownController implements Initializable{
    
    @FXML
    private Label labTime;
    @FXML
    private Button buttSTOP;
    
    private Timer timer = new Timer(true); //set it as a deamon
    private int iHours = 0,
                iMinutes = 1,
                iSeconds = 10;  
    
    
    public void initCountdownController(int iHours, int iMinutes, int iSeconds){
        this.iHours = iHours;
        this.iMinutes = iMinutes;
        this.iSeconds = iSeconds;
    }
    @Override
    public void initialize(URL location, ResourceBundle resources) {
        buttSTOP.setOnAction(e -> {
            buttSTOPAction(e);
        });
        timer.schedule(new MyTimer(), 0, 1000);
    }
    private void buttSTOPAction(ActionEvent e) {
        timer.cancel();
    }
    public class MyTimer extends TimerTask{
        @Override
        public void run() {
            String time = iHours + ":" + iMinutes + ":" + iSeconds;
            Platform.runLater(() -> {
                labTime.setText(time);
            });
    
            if(iSeconds < 1)
                if(iMinutes < 1)
                    if(iHours < 1)
                        this.cancel();
                    else{
                        iHours--;
                        iMinutes = 59;
                        iSeconds = 59;
                    }
                else{
                    iMinutes--;
                    iSeconds = 59;
                }
            else
                iSeconds--;
        }
    }
    
    0 讨论(0)
  • 2021-01-15 02:13

    Part I

    A thread, when created, runs independent of other threads. You have a new thread which has an infinite loop, which implies, it will keep running forever, even after the stage has been closed.

    Normally, using a infinite loop is not advised, because breaking out of it is very difficult.

    You are advised to use :

    • TimerTask
    • ScheduledExecutorService

    You can then call either one of them (based on whatever you are using)

    • TimerTask.cancel()
    • ScheduledExecutorService.shutdownNow()

    when your stage is closed. You can use something like :

    stage.setOnCloseRequest(closeEvent -> {
           timertask.cancel();  
    });  
    

    JavaFX API's (thanks to James_D comment's)

    These do not need to be explicitly canceled as ScheduledService uses daemon threads and AnimationTimer runs on the JavaFX thread.

    • ScheduledService
    • AnimationTimer

    Part II

    Your second part of the question has been answered time and again in the forum.

    You need to be on the JavaFX Application thread to use scene graph elements.

    Since you have created a new thread and trying to update label, which is a JavaFX node, it throws the exception. For more information, please visit:

    JavaFX error when trying to remove shape

    Why am I getting java.lang.IllegalStateException "Not on FX application thread" on JavaFX?

    Javafx Not on fx application thread when using timer

    0 讨论(0)
提交回复
热议问题