How to get a scheduled event to interact with JavaFX GUI












1















I'm a beginner Java programmer trying to figure this out. I have a piece of code that does some calculation and updates a label in my JavaFX GUI. It runs every 100ms using a ScheduledExecutorService and a Runnable. The problem is it cannot update the Label of the GUI. I have spent yesterday looking for a way to do it and most of the topics seem to be solved with the use of Platform.runLater but even putting my code into the runLater runnable seems to still not work. Another thing I have found is using the Java concurrency framework, but I don't know how to use that for a repeating scheduled service like this. Here's how I wrote the code:



ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
Runnable loop = new Runnable() {
public void run() {
Platform.runLater(new Runnable() {
@Override public void run() {
double result = calculation();
labelResult.setText("" + result);
}
});
}
};
executor.scheduleAtFixedRate(loop, 0, 100, TimeUnit.MILLISECONDS);


How could I do this?



EDIT:
I'm including a full example.
Main class:



import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javafx.application.Application;
import javafx.application.Platform;

public class Main{
private static long value = 0;
private static Gui gui;

public static void main(String args){

ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
Runnable loop = new Runnable() {
public void run() {
Platform.runLater(new Runnable() {
@Override public void run() {
calculate();
}
});
}
};
executor.scheduleAtFixedRate(loop, 0, 100, TimeUnit.MILLISECONDS);

Application.launch(Gui.class, args);
}

public static void calculate(){
double result = value++;
gui.setResult(result);
}

public static void setGui(Gui ref){
gui = ref;
}
}


Gui class:



import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

public class Gui extends Application{
private Stage window;
private Scene scene;
private HBox layout = new HBox();
private Label result = new Label("TEST");

@Override
public void start(Stage stage) throws Exception {
window = stage;

layout.getChildren().addAll(result);

Main.setGui(this);

scene = new Scene(layout, 1280, 720);
window.setTitle("Example");
window.setResizable(false);
window.setScene(scene);
window.show();
}

public void setResult(double res){
result.setText("" + res);
}
}









share|improve this question





























    1















    I'm a beginner Java programmer trying to figure this out. I have a piece of code that does some calculation and updates a label in my JavaFX GUI. It runs every 100ms using a ScheduledExecutorService and a Runnable. The problem is it cannot update the Label of the GUI. I have spent yesterday looking for a way to do it and most of the topics seem to be solved with the use of Platform.runLater but even putting my code into the runLater runnable seems to still not work. Another thing I have found is using the Java concurrency framework, but I don't know how to use that for a repeating scheduled service like this. Here's how I wrote the code:



    ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
    Runnable loop = new Runnable() {
    public void run() {
    Platform.runLater(new Runnable() {
    @Override public void run() {
    double result = calculation();
    labelResult.setText("" + result);
    }
    });
    }
    };
    executor.scheduleAtFixedRate(loop, 0, 100, TimeUnit.MILLISECONDS);


    How could I do this?



    EDIT:
    I'm including a full example.
    Main class:



    import java.util.concurrent.Executors;
    import java.util.concurrent.ScheduledExecutorService;
    import java.util.concurrent.TimeUnit;
    import javafx.application.Application;
    import javafx.application.Platform;

    public class Main{
    private static long value = 0;
    private static Gui gui;

    public static void main(String args){

    ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
    Runnable loop = new Runnable() {
    public void run() {
    Platform.runLater(new Runnable() {
    @Override public void run() {
    calculate();
    }
    });
    }
    };
    executor.scheduleAtFixedRate(loop, 0, 100, TimeUnit.MILLISECONDS);

    Application.launch(Gui.class, args);
    }

    public static void calculate(){
    double result = value++;
    gui.setResult(result);
    }

    public static void setGui(Gui ref){
    gui = ref;
    }
    }


    Gui class:



    import javafx.application.Application;
    import javafx.scene.Scene;
    import javafx.scene.control.Label;
    import javafx.scene.layout.HBox;
    import javafx.stage.Stage;

    public class Gui extends Application{
    private Stage window;
    private Scene scene;
    private HBox layout = new HBox();
    private Label result = new Label("TEST");

    @Override
    public void start(Stage stage) throws Exception {
    window = stage;

    layout.getChildren().addAll(result);

    Main.setGui(this);

    scene = new Scene(layout, 1280, 720);
    window.setTitle("Example");
    window.setResizable(false);
    window.setScene(scene);
    window.show();
    }

    public void setResult(double res){
    result.setText("" + res);
    }
    }









    share|improve this question



























      1












      1








      1


      1






      I'm a beginner Java programmer trying to figure this out. I have a piece of code that does some calculation and updates a label in my JavaFX GUI. It runs every 100ms using a ScheduledExecutorService and a Runnable. The problem is it cannot update the Label of the GUI. I have spent yesterday looking for a way to do it and most of the topics seem to be solved with the use of Platform.runLater but even putting my code into the runLater runnable seems to still not work. Another thing I have found is using the Java concurrency framework, but I don't know how to use that for a repeating scheduled service like this. Here's how I wrote the code:



      ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
      Runnable loop = new Runnable() {
      public void run() {
      Platform.runLater(new Runnable() {
      @Override public void run() {
      double result = calculation();
      labelResult.setText("" + result);
      }
      });
      }
      };
      executor.scheduleAtFixedRate(loop, 0, 100, TimeUnit.MILLISECONDS);


      How could I do this?



      EDIT:
      I'm including a full example.
      Main class:



      import java.util.concurrent.Executors;
      import java.util.concurrent.ScheduledExecutorService;
      import java.util.concurrent.TimeUnit;
      import javafx.application.Application;
      import javafx.application.Platform;

      public class Main{
      private static long value = 0;
      private static Gui gui;

      public static void main(String args){

      ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
      Runnable loop = new Runnable() {
      public void run() {
      Platform.runLater(new Runnable() {
      @Override public void run() {
      calculate();
      }
      });
      }
      };
      executor.scheduleAtFixedRate(loop, 0, 100, TimeUnit.MILLISECONDS);

      Application.launch(Gui.class, args);
      }

      public static void calculate(){
      double result = value++;
      gui.setResult(result);
      }

      public static void setGui(Gui ref){
      gui = ref;
      }
      }


      Gui class:



      import javafx.application.Application;
      import javafx.scene.Scene;
      import javafx.scene.control.Label;
      import javafx.scene.layout.HBox;
      import javafx.stage.Stage;

      public class Gui extends Application{
      private Stage window;
      private Scene scene;
      private HBox layout = new HBox();
      private Label result = new Label("TEST");

      @Override
      public void start(Stage stage) throws Exception {
      window = stage;

      layout.getChildren().addAll(result);

      Main.setGui(this);

      scene = new Scene(layout, 1280, 720);
      window.setTitle("Example");
      window.setResizable(false);
      window.setScene(scene);
      window.show();
      }

      public void setResult(double res){
      result.setText("" + res);
      }
      }









      share|improve this question
















      I'm a beginner Java programmer trying to figure this out. I have a piece of code that does some calculation and updates a label in my JavaFX GUI. It runs every 100ms using a ScheduledExecutorService and a Runnable. The problem is it cannot update the Label of the GUI. I have spent yesterday looking for a way to do it and most of the topics seem to be solved with the use of Platform.runLater but even putting my code into the runLater runnable seems to still not work. Another thing I have found is using the Java concurrency framework, but I don't know how to use that for a repeating scheduled service like this. Here's how I wrote the code:



      ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
      Runnable loop = new Runnable() {
      public void run() {
      Platform.runLater(new Runnable() {
      @Override public void run() {
      double result = calculation();
      labelResult.setText("" + result);
      }
      });
      }
      };
      executor.scheduleAtFixedRate(loop, 0, 100, TimeUnit.MILLISECONDS);


      How could I do this?



      EDIT:
      I'm including a full example.
      Main class:



      import java.util.concurrent.Executors;
      import java.util.concurrent.ScheduledExecutorService;
      import java.util.concurrent.TimeUnit;
      import javafx.application.Application;
      import javafx.application.Platform;

      public class Main{
      private static long value = 0;
      private static Gui gui;

      public static void main(String args){

      ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
      Runnable loop = new Runnable() {
      public void run() {
      Platform.runLater(new Runnable() {
      @Override public void run() {
      calculate();
      }
      });
      }
      };
      executor.scheduleAtFixedRate(loop, 0, 100, TimeUnit.MILLISECONDS);

      Application.launch(Gui.class, args);
      }

      public static void calculate(){
      double result = value++;
      gui.setResult(result);
      }

      public static void setGui(Gui ref){
      gui = ref;
      }
      }


      Gui class:



      import javafx.application.Application;
      import javafx.scene.Scene;
      import javafx.scene.control.Label;
      import javafx.scene.layout.HBox;
      import javafx.stage.Stage;

      public class Gui extends Application{
      private Stage window;
      private Scene scene;
      private HBox layout = new HBox();
      private Label result = new Label("TEST");

      @Override
      public void start(Stage stage) throws Exception {
      window = stage;

      layout.getChildren().addAll(result);

      Main.setGui(this);

      scene = new Scene(layout, 1280, 720);
      window.setTitle("Example");
      window.setResizable(false);
      window.setScene(scene);
      window.show();
      }

      public void setResult(double res){
      result.setText("" + res);
      }
      }






      java user-interface javafx concurrency scheduled-tasks






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Jun 10 '17 at 15:06









      Blasanka

      3,54642134




      3,54642134










      asked Jun 10 '17 at 14:22









      Kamil MarkiewiczKamil Markiewicz

      1517




      1517
























          1 Answer
          1






          active

          oldest

          votes


















          1














          The overall structure of your application is wrong. The reason that your scheduled executor service is failing is that you attempt to start it before you launch the JavaFX application, and consequently your first call to Platform.runLater(...) happens before the FX toolkit has been started and before the FX Application Thread is running.



          If you wrap the call to Platform.runLater() in a try block and catch the exception:



          Runnable loop = new Runnable() {
          public void run() {
          try {
          Platform.runLater(new Runnable() {
          @Override
          public void run() {
          calculate();
          }
          });
          } catch (Exception e) {
          e.printStackTrace();
          }
          }
          };


          you will see the exception:



          java.lang.IllegalStateException: Toolkit not initialized
          at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:273)
          at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:268)
          at javafx.application.Platform.runLater(Platform.java:83)
          at Main$1.run(Main.java:17)
          at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
          at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
          at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180)
          at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
          at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
          at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
          at java.lang.Thread.run(Thread.java:745)


          (Incidentally, handling the exception will also allow the executor to continue, so eventually it will "recover" as the toolkit will be started at some point. You may also see other exceptions, because, e.g. there are race conditions on the gui field: some iterations of the executor may get called before gui is initialized.)



          You should think of the Application.start() method essentially as the entry point for the application. When you call launch() (or when it is called for you, which happens in most final deployment scenarios), the FX Toolkit is started, then an instance of the Application subclass is created, and start() is invoked on that instance on the FX Application Thread.



          So the way to structure this is to drive it all from the start() method. Create an instance of your GUI class there, create an instance of the class that is running your scheduled executor, tie them together, and then just display the UI in the provided stage. Here's one possible example of this refactoring:



          Main.java:



          import javafx.application.Application;
          import javafx.stage.Stage;

          public class Main extends Application{
          private Stage window;

          @Override
          public void start(Stage stage) throws Exception {
          window = stage;

          Gui gui = new Gui();
          UpdateService service = new UpdateService(gui);
          service.startService();

          window.setTitle("Example");
          window.setResizable(false);
          window.setScene(gui.getScene());
          window.show();
          }

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


          }


          UpdateService.java:



          import java.util.concurrent.Executors;
          import java.util.concurrent.ScheduledExecutorService;
          import java.util.concurrent.TimeUnit;

          import javafx.application.Platform;

          public class UpdateService {
          private long value = 0;
          private final Gui gui;

          public UpdateService(Gui gui) {
          this.gui = gui;
          }

          public void startService() {

          // create executor that uses daemon threads;
          ScheduledExecutorService executor = Executors.newScheduledThreadPool(1, runnable -> {
          Thread t = new Thread(runnable);
          t.setDaemon(true);
          return t;
          });
          Runnable loop = new Runnable() {
          public void run() {
          Platform.runLater(new Runnable() {
          @Override
          public void run() {
          calculate();
          }
          });
          }
          };

          executor.scheduleAtFixedRate(loop, 0, 100, TimeUnit.MILLISECONDS);

          }

          public void calculate() {
          double result = value++;
          gui.setResult(result);
          }

          }


          Gui.java:



          import javafx.scene.Scene;
          import javafx.scene.control.Label;
          import javafx.scene.layout.HBox;

          public class Gui {

          private Scene scene;
          private HBox layout = new HBox();
          private Label result = new Label("TEST");

          public Gui() {
          layout.getChildren().addAll(result);
          scene = new Scene(layout, 1280, 720);
          }

          public Scene getScene() {
          return scene ;
          }

          public void setResult(double res){
          result.setText("" + res);
          }
          }


          Finally, note that a cleaner way to get regularly-repeating functionality that runs on the FX Application Thread is to use the Animation API (as in JavaFX periodic background task):



          public void startService() {
          Timeline timeline = new Timeline(new KeyFrame(Duration.millis(100), e -> calculate()));
          timeline.setCycleCount(Animation.INDEFINITE);
          timeline.play();
          }





          share|improve this answer

























            Your Answer






            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "1"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f44474391%2fhow-to-get-a-scheduled-event-to-interact-with-javafx-gui%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            1














            The overall structure of your application is wrong. The reason that your scheduled executor service is failing is that you attempt to start it before you launch the JavaFX application, and consequently your first call to Platform.runLater(...) happens before the FX toolkit has been started and before the FX Application Thread is running.



            If you wrap the call to Platform.runLater() in a try block and catch the exception:



            Runnable loop = new Runnable() {
            public void run() {
            try {
            Platform.runLater(new Runnable() {
            @Override
            public void run() {
            calculate();
            }
            });
            } catch (Exception e) {
            e.printStackTrace();
            }
            }
            };


            you will see the exception:



            java.lang.IllegalStateException: Toolkit not initialized
            at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:273)
            at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:268)
            at javafx.application.Platform.runLater(Platform.java:83)
            at Main$1.run(Main.java:17)
            at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
            at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
            at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180)
            at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
            at java.lang.Thread.run(Thread.java:745)


            (Incidentally, handling the exception will also allow the executor to continue, so eventually it will "recover" as the toolkit will be started at some point. You may also see other exceptions, because, e.g. there are race conditions on the gui field: some iterations of the executor may get called before gui is initialized.)



            You should think of the Application.start() method essentially as the entry point for the application. When you call launch() (or when it is called for you, which happens in most final deployment scenarios), the FX Toolkit is started, then an instance of the Application subclass is created, and start() is invoked on that instance on the FX Application Thread.



            So the way to structure this is to drive it all from the start() method. Create an instance of your GUI class there, create an instance of the class that is running your scheduled executor, tie them together, and then just display the UI in the provided stage. Here's one possible example of this refactoring:



            Main.java:



            import javafx.application.Application;
            import javafx.stage.Stage;

            public class Main extends Application{
            private Stage window;

            @Override
            public void start(Stage stage) throws Exception {
            window = stage;

            Gui gui = new Gui();
            UpdateService service = new UpdateService(gui);
            service.startService();

            window.setTitle("Example");
            window.setResizable(false);
            window.setScene(gui.getScene());
            window.show();
            }

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


            }


            UpdateService.java:



            import java.util.concurrent.Executors;
            import java.util.concurrent.ScheduledExecutorService;
            import java.util.concurrent.TimeUnit;

            import javafx.application.Platform;

            public class UpdateService {
            private long value = 0;
            private final Gui gui;

            public UpdateService(Gui gui) {
            this.gui = gui;
            }

            public void startService() {

            // create executor that uses daemon threads;
            ScheduledExecutorService executor = Executors.newScheduledThreadPool(1, runnable -> {
            Thread t = new Thread(runnable);
            t.setDaemon(true);
            return t;
            });
            Runnable loop = new Runnable() {
            public void run() {
            Platform.runLater(new Runnable() {
            @Override
            public void run() {
            calculate();
            }
            });
            }
            };

            executor.scheduleAtFixedRate(loop, 0, 100, TimeUnit.MILLISECONDS);

            }

            public void calculate() {
            double result = value++;
            gui.setResult(result);
            }

            }


            Gui.java:



            import javafx.scene.Scene;
            import javafx.scene.control.Label;
            import javafx.scene.layout.HBox;

            public class Gui {

            private Scene scene;
            private HBox layout = new HBox();
            private Label result = new Label("TEST");

            public Gui() {
            layout.getChildren().addAll(result);
            scene = new Scene(layout, 1280, 720);
            }

            public Scene getScene() {
            return scene ;
            }

            public void setResult(double res){
            result.setText("" + res);
            }
            }


            Finally, note that a cleaner way to get regularly-repeating functionality that runs on the FX Application Thread is to use the Animation API (as in JavaFX periodic background task):



            public void startService() {
            Timeline timeline = new Timeline(new KeyFrame(Duration.millis(100), e -> calculate()));
            timeline.setCycleCount(Animation.INDEFINITE);
            timeline.play();
            }





            share|improve this answer






























              1














              The overall structure of your application is wrong. The reason that your scheduled executor service is failing is that you attempt to start it before you launch the JavaFX application, and consequently your first call to Platform.runLater(...) happens before the FX toolkit has been started and before the FX Application Thread is running.



              If you wrap the call to Platform.runLater() in a try block and catch the exception:



              Runnable loop = new Runnable() {
              public void run() {
              try {
              Platform.runLater(new Runnable() {
              @Override
              public void run() {
              calculate();
              }
              });
              } catch (Exception e) {
              e.printStackTrace();
              }
              }
              };


              you will see the exception:



              java.lang.IllegalStateException: Toolkit not initialized
              at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:273)
              at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:268)
              at javafx.application.Platform.runLater(Platform.java:83)
              at Main$1.run(Main.java:17)
              at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
              at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
              at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180)
              at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
              at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
              at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
              at java.lang.Thread.run(Thread.java:745)


              (Incidentally, handling the exception will also allow the executor to continue, so eventually it will "recover" as the toolkit will be started at some point. You may also see other exceptions, because, e.g. there are race conditions on the gui field: some iterations of the executor may get called before gui is initialized.)



              You should think of the Application.start() method essentially as the entry point for the application. When you call launch() (or when it is called for you, which happens in most final deployment scenarios), the FX Toolkit is started, then an instance of the Application subclass is created, and start() is invoked on that instance on the FX Application Thread.



              So the way to structure this is to drive it all from the start() method. Create an instance of your GUI class there, create an instance of the class that is running your scheduled executor, tie them together, and then just display the UI in the provided stage. Here's one possible example of this refactoring:



              Main.java:



              import javafx.application.Application;
              import javafx.stage.Stage;

              public class Main extends Application{
              private Stage window;

              @Override
              public void start(Stage stage) throws Exception {
              window = stage;

              Gui gui = new Gui();
              UpdateService service = new UpdateService(gui);
              service.startService();

              window.setTitle("Example");
              window.setResizable(false);
              window.setScene(gui.getScene());
              window.show();
              }

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


              }


              UpdateService.java:



              import java.util.concurrent.Executors;
              import java.util.concurrent.ScheduledExecutorService;
              import java.util.concurrent.TimeUnit;

              import javafx.application.Platform;

              public class UpdateService {
              private long value = 0;
              private final Gui gui;

              public UpdateService(Gui gui) {
              this.gui = gui;
              }

              public void startService() {

              // create executor that uses daemon threads;
              ScheduledExecutorService executor = Executors.newScheduledThreadPool(1, runnable -> {
              Thread t = new Thread(runnable);
              t.setDaemon(true);
              return t;
              });
              Runnable loop = new Runnable() {
              public void run() {
              Platform.runLater(new Runnable() {
              @Override
              public void run() {
              calculate();
              }
              });
              }
              };

              executor.scheduleAtFixedRate(loop, 0, 100, TimeUnit.MILLISECONDS);

              }

              public void calculate() {
              double result = value++;
              gui.setResult(result);
              }

              }


              Gui.java:



              import javafx.scene.Scene;
              import javafx.scene.control.Label;
              import javafx.scene.layout.HBox;

              public class Gui {

              private Scene scene;
              private HBox layout = new HBox();
              private Label result = new Label("TEST");

              public Gui() {
              layout.getChildren().addAll(result);
              scene = new Scene(layout, 1280, 720);
              }

              public Scene getScene() {
              return scene ;
              }

              public void setResult(double res){
              result.setText("" + res);
              }
              }


              Finally, note that a cleaner way to get regularly-repeating functionality that runs on the FX Application Thread is to use the Animation API (as in JavaFX periodic background task):



              public void startService() {
              Timeline timeline = new Timeline(new KeyFrame(Duration.millis(100), e -> calculate()));
              timeline.setCycleCount(Animation.INDEFINITE);
              timeline.play();
              }





              share|improve this answer




























                1












                1








                1







                The overall structure of your application is wrong. The reason that your scheduled executor service is failing is that you attempt to start it before you launch the JavaFX application, and consequently your first call to Platform.runLater(...) happens before the FX toolkit has been started and before the FX Application Thread is running.



                If you wrap the call to Platform.runLater() in a try block and catch the exception:



                Runnable loop = new Runnable() {
                public void run() {
                try {
                Platform.runLater(new Runnable() {
                @Override
                public void run() {
                calculate();
                }
                });
                } catch (Exception e) {
                e.printStackTrace();
                }
                }
                };


                you will see the exception:



                java.lang.IllegalStateException: Toolkit not initialized
                at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:273)
                at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:268)
                at javafx.application.Platform.runLater(Platform.java:83)
                at Main$1.run(Main.java:17)
                at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
                at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
                at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180)
                at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
                at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
                at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
                at java.lang.Thread.run(Thread.java:745)


                (Incidentally, handling the exception will also allow the executor to continue, so eventually it will "recover" as the toolkit will be started at some point. You may also see other exceptions, because, e.g. there are race conditions on the gui field: some iterations of the executor may get called before gui is initialized.)



                You should think of the Application.start() method essentially as the entry point for the application. When you call launch() (or when it is called for you, which happens in most final deployment scenarios), the FX Toolkit is started, then an instance of the Application subclass is created, and start() is invoked on that instance on the FX Application Thread.



                So the way to structure this is to drive it all from the start() method. Create an instance of your GUI class there, create an instance of the class that is running your scheduled executor, tie them together, and then just display the UI in the provided stage. Here's one possible example of this refactoring:



                Main.java:



                import javafx.application.Application;
                import javafx.stage.Stage;

                public class Main extends Application{
                private Stage window;

                @Override
                public void start(Stage stage) throws Exception {
                window = stage;

                Gui gui = new Gui();
                UpdateService service = new UpdateService(gui);
                service.startService();

                window.setTitle("Example");
                window.setResizable(false);
                window.setScene(gui.getScene());
                window.show();
                }

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


                }


                UpdateService.java:



                import java.util.concurrent.Executors;
                import java.util.concurrent.ScheduledExecutorService;
                import java.util.concurrent.TimeUnit;

                import javafx.application.Platform;

                public class UpdateService {
                private long value = 0;
                private final Gui gui;

                public UpdateService(Gui gui) {
                this.gui = gui;
                }

                public void startService() {

                // create executor that uses daemon threads;
                ScheduledExecutorService executor = Executors.newScheduledThreadPool(1, runnable -> {
                Thread t = new Thread(runnable);
                t.setDaemon(true);
                return t;
                });
                Runnable loop = new Runnable() {
                public void run() {
                Platform.runLater(new Runnable() {
                @Override
                public void run() {
                calculate();
                }
                });
                }
                };

                executor.scheduleAtFixedRate(loop, 0, 100, TimeUnit.MILLISECONDS);

                }

                public void calculate() {
                double result = value++;
                gui.setResult(result);
                }

                }


                Gui.java:



                import javafx.scene.Scene;
                import javafx.scene.control.Label;
                import javafx.scene.layout.HBox;

                public class Gui {

                private Scene scene;
                private HBox layout = new HBox();
                private Label result = new Label("TEST");

                public Gui() {
                layout.getChildren().addAll(result);
                scene = new Scene(layout, 1280, 720);
                }

                public Scene getScene() {
                return scene ;
                }

                public void setResult(double res){
                result.setText("" + res);
                }
                }


                Finally, note that a cleaner way to get regularly-repeating functionality that runs on the FX Application Thread is to use the Animation API (as in JavaFX periodic background task):



                public void startService() {
                Timeline timeline = new Timeline(new KeyFrame(Duration.millis(100), e -> calculate()));
                timeline.setCycleCount(Animation.INDEFINITE);
                timeline.play();
                }





                share|improve this answer















                The overall structure of your application is wrong. The reason that your scheduled executor service is failing is that you attempt to start it before you launch the JavaFX application, and consequently your first call to Platform.runLater(...) happens before the FX toolkit has been started and before the FX Application Thread is running.



                If you wrap the call to Platform.runLater() in a try block and catch the exception:



                Runnable loop = new Runnable() {
                public void run() {
                try {
                Platform.runLater(new Runnable() {
                @Override
                public void run() {
                calculate();
                }
                });
                } catch (Exception e) {
                e.printStackTrace();
                }
                }
                };


                you will see the exception:



                java.lang.IllegalStateException: Toolkit not initialized
                at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:273)
                at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:268)
                at javafx.application.Platform.runLater(Platform.java:83)
                at Main$1.run(Main.java:17)
                at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
                at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
                at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180)
                at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
                at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
                at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
                at java.lang.Thread.run(Thread.java:745)


                (Incidentally, handling the exception will also allow the executor to continue, so eventually it will "recover" as the toolkit will be started at some point. You may also see other exceptions, because, e.g. there are race conditions on the gui field: some iterations of the executor may get called before gui is initialized.)



                You should think of the Application.start() method essentially as the entry point for the application. When you call launch() (or when it is called for you, which happens in most final deployment scenarios), the FX Toolkit is started, then an instance of the Application subclass is created, and start() is invoked on that instance on the FX Application Thread.



                So the way to structure this is to drive it all from the start() method. Create an instance of your GUI class there, create an instance of the class that is running your scheduled executor, tie them together, and then just display the UI in the provided stage. Here's one possible example of this refactoring:



                Main.java:



                import javafx.application.Application;
                import javafx.stage.Stage;

                public class Main extends Application{
                private Stage window;

                @Override
                public void start(Stage stage) throws Exception {
                window = stage;

                Gui gui = new Gui();
                UpdateService service = new UpdateService(gui);
                service.startService();

                window.setTitle("Example");
                window.setResizable(false);
                window.setScene(gui.getScene());
                window.show();
                }

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


                }


                UpdateService.java:



                import java.util.concurrent.Executors;
                import java.util.concurrent.ScheduledExecutorService;
                import java.util.concurrent.TimeUnit;

                import javafx.application.Platform;

                public class UpdateService {
                private long value = 0;
                private final Gui gui;

                public UpdateService(Gui gui) {
                this.gui = gui;
                }

                public void startService() {

                // create executor that uses daemon threads;
                ScheduledExecutorService executor = Executors.newScheduledThreadPool(1, runnable -> {
                Thread t = new Thread(runnable);
                t.setDaemon(true);
                return t;
                });
                Runnable loop = new Runnable() {
                public void run() {
                Platform.runLater(new Runnable() {
                @Override
                public void run() {
                calculate();
                }
                });
                }
                };

                executor.scheduleAtFixedRate(loop, 0, 100, TimeUnit.MILLISECONDS);

                }

                public void calculate() {
                double result = value++;
                gui.setResult(result);
                }

                }


                Gui.java:



                import javafx.scene.Scene;
                import javafx.scene.control.Label;
                import javafx.scene.layout.HBox;

                public class Gui {

                private Scene scene;
                private HBox layout = new HBox();
                private Label result = new Label("TEST");

                public Gui() {
                layout.getChildren().addAll(result);
                scene = new Scene(layout, 1280, 720);
                }

                public Scene getScene() {
                return scene ;
                }

                public void setResult(double res){
                result.setText("" + res);
                }
                }


                Finally, note that a cleaner way to get regularly-repeating functionality that runs on the FX Application Thread is to use the Animation API (as in JavaFX periodic background task):



                public void startService() {
                Timeline timeline = new Timeline(new KeyFrame(Duration.millis(100), e -> calculate()));
                timeline.setCycleCount(Animation.INDEFINITE);
                timeline.play();
                }






                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited Nov 21 '18 at 12:36









                Matthias Wimmer

                2,085925




                2,085925










                answered Jun 10 '17 at 15:16









                James_DJames_D

                141k9161204




                141k9161204
































                    draft saved

                    draft discarded




















































                    Thanks for contributing an answer to Stack Overflow!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f44474391%2fhow-to-get-a-scheduled-event-to-interact-with-javafx-gui%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Can a sorcerer learn a 5th-level spell early by creating spell slots using the Font of Magic feature?

                    Does disintegrating a polymorphed enemy still kill it after the 2018 errata?

                    A Topological Invariant for $pi_3(U(n))$