New topic, the application still works after the closing phase

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

and I made exactly the same code in javafx8.

public class CountdownController implements Initializable{ @FXML private Label labTime; @Override public void initialize(URL location, ResourceBundle resources) { new Thread(){ public void run(){ while(true){ 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; labTime.setText(time); } } }.start(); } 

After closing the window, the application / thread is still working on the system. My guess is because there is an infinite loop, but shouldn't the thread end with closing the application?

Secondly, when I try to set the text for the label, I get an error message:

 Exception in thread "Thread-4" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-4 at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:204) at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:364) at javafx.scene.Parent$2.onProposedChange(Parent.java:364) at com.sun.javafx.collections.VetoableListDecorator.setAll(VetoableListDecorator.java:113) at com.sun.javafx.collections.VetoableListDecorator.setAll(VetoableListDecorator.java:108) at com.sun.javafx.scene.control.skin.LabeledSkinBase.updateChildren(LabeledSkinBase.java:575) at com.sun.javafx.scene.control.skin.LabeledSkinBase.handleControlPropertyChanged(LabeledSkinBase.java:204) at com.sun.javafx.scene.control.skin.LabelSkin.handleControlPropertyChanged(LabelSkin.java:49) at com.sun.javafx.scene.control.skin.BehaviorSkinBase.lambda$registerChangeListener$60(BehaviorSkinBase.java:197) at com.sun.javafx.scene.control.skin.BehaviorSkinBase$$Lambda$144/1099655841.call(Unknown Source) at com.sun.javafx.scene.control.MultiplePropertyChangeListenerHandler$1.changed(MultiplePropertyChangeListenerHandler.java:55) at javafx.beans.value.WeakChangeListener.changed(WeakChangeListener.java:89) at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:182) at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81) at javafx.beans.property.StringPropertyBase.fireValueChangedEvent(StringPropertyBase.java:103) at javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:110) at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:143) at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:49) at javafx.beans.property.StringProperty.setValue(StringProperty.java:65) at javafx.scene.control.Labeled.setText(Labeled.java:146) at application.CountdownController$1.run(CountdownController.java:29) 

... yes, I will read more about streams, but I would like to know the answer to these questions.

+2
multithreading javafx-8
source share
2 answers

Part I

The thread at creation is launched independently of other threads. You have a new thread with an infinite loop, which implies that it will continue to work forever, even after the stage closes.

As a rule, the use of an infinite loop is not recommended, as its presentation is very difficult.

You are advised to use:

Then you can call any of them (based on what you use)

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

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

JavaFX API (thanks to James_D comments)

They should not be explicitly canceled, because the ScheduledService uses daemon threads and AnimationTimer works in the JavaFX thread.

Part II

Your second part of the question was received again and again on the forum.

You need to be in the JavaFX application thread to use scene graph elements.

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

JavaFX error while trying to delete form

Why am I getting java.lang.IllegalStateException "Not in the FX application stream" in JavaFX?

Javafx Do not use fx application thread when using timer

+3
source share

With the ScheduledExecutorService as far as I can tell, you cannot easily install it as deamon, and I do not want to play with stage.setOnCloseRequest(closeEvent -> {});

With AnimationTimer I cannot do something like Thread.sleep(100) between iterations, as you expected, because "AnimationTimer works in JavaFX stream".

ScheduledService is just hard for me to understand right now ...

so when I read and read about it, I came to the conclusion that perhaps this simple option would be better:

 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 to James_D and ItachiUchiha . It works, let me know if I am missing something!

EDIT: I also include code for time tracking, as that was my original goal, maybe someone will find this useful 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--; } } 
+1
source share

All Articles