2

It is the first time that I use the java swing timer. My goal is to update the label once per sec, but when I run the program, an error occures. To make sure that it justs bugs with the labels, I tried to insert a progressbar that should get slowly filled, and it worked. How am i supposed to do?

This is my main class:

package Application;

import java.io.IOException;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class main extends Application {

    @Override
    public void start(Stage primaryStage) throws IOException {
        Parent root =   FXMLLoader.load(getClass().getResource("/Interface/interface.fxml"));
        Scene scene = new Scene (root);

        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

Here is the main controller of my fxml document:

package Application;

import java.awt.event.ActionListener;
import java.net.URL;
import java.util.ResourceBundle;

import javax.swing.Timer;

import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;

public class MainController implements Initializable {

    @Override
    public void initialize(URL arg0, ResourceBundle arg1) {
        // TODO Auto-generated method stub

    }

    @FXML
    Label label;
    double count = 0.0;

    public void ok(ActionEvent event){
        ActionListener action = new ActionListener(){

            @Override
            public void actionPerformed(java.awt.event.ActionEvent arg0) {
                count+=0.1;
                label.setText(count+"");
            }
        };

        Timer timer = new Timer(1000, action);
        timer.start();
    }
}

That is it. I got a button that is supposed to start the Timer "timer" that is supposed to change the Label "label". The method "ok" is the one called when the button is pressed. And, as I already said, it is supposed to start the timer. But when i do so, i get an error:

Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Not on FX application thread; currentThread = AWT-EventQueue-0
    at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:236)
    at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:423)
    at javafx.scene.Parent$2.onProposedChange(Parent.java:367)
    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$61(BehaviorSkinBase.java:197)
    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:144)
    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:145)
    at Application.MainController$1.actionPerformed(MainController.java:46)
    at javax.swing.Timer.fireActionPerformed(Unknown Source)
    at javax.swing.Timer$DoPostEvent.run(Unknown Source)
    at java.awt.event.InvocationEvent.dispatch(Unknown Source)
    at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
    at java.awt.EventQueue.access$500(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue.dispatchEvent(Unknown Source)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.run(Unknown Source)

What can i do?

GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • Possibly related: http://stackoverflow.com/questions/12182592/javafx-2-x-swing-not-on-fx-application-thread – jsheeran Sep 14 '16 at 11:51
  • Swing is not exactly compatible with JavaFX. They have separate event handling threads. – RealSkeptic Sep 14 '16 at 11:53
  • http://stackoverflow.com/questions/9966136/javafx-periodic-background-task - see Timeline maybe. – Joop Eggen Sep 14 '16 at 12:00
  • Hint: next time, please take the few minutes it takes to properly format your source code snippets. And: did my answer help you? If not, anything missing? – GhostCat Sep 14 '16 at 13:20

1 Answers1

3

Similar to Swing, there is a special thread that you need to run "inside" to do your UI updates - the Java FX event dispatch thread, which handles all GUI-related tasks.

You need to use Platform.runLater() here.

In other words: you need to define a Runnable that makes the update; and then you pass an instance of that Runnable to the afore mentioned runLater().

You error message is basically telling you that FX doesn't want you to make updates in any other thread!

Besides: it shouldn't directly matter, but probably you better use java.util.Timer instead of java.Swing.Timer.

EDIT: you need something like this; assuming that you want things to be triggered by your ok() method:

public void ok(ActionEvent event){
    final Runnable update = new Runnable() {
       @Override 
       public void run() {
         count+=0.1;
         label.setText(count+"");
        }
    };

   ActionListener delayedAction = new ActionListener(){
     @Override
     public void actionPerformed(java.awt.event.ActionEvent arg0) {
       Platform.runLater(update);
     }
   };

   new Timer(1000, delayedAction).start();
}

    Platform.runLater(update);
}

The above does:

A) create a Runnable object that will update your UI element

B) use the "known" Swing Timer to invoke that Runnable using the required Platform.runLater() call

That should work, but might require some fine tuning (code is neither compiled nor tested).

GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • I've tried to use the java.util.timer too and it showed exactly the same error for updating the label. You've talked about the Platform.runlater, but i am very new to java, so could you or anyone give me a full example of how i should write down the timer code? Please. – Selim Makhoul Sep 15 '16 at 05:41
  • Of course changing the Timer doesn't solve the problem. That is what the whole answer is about! Anyway, I put in some (untested, uncompiled) example code for you to play with. But, **honestly** if you really do not understand that *simple* meaning of the Platform.updateLater(); and you are unable to do some research on that, then seriously: you shouldn't do JavaFX UI programming as of now. You are simply lacking very **basic knowledge** about Java. You try to run; but your are hardly able to crawl. Thus: I would recommend you to "pause" Java FX for a while; and focusing on learning about ... – GhostCat Sep 15 '16 at 06:00
  • such basics. But of course: try my code input; and if it works; feel free to accept my answer ;-) – GhostCat Sep 15 '16 at 06:00