stop for X seconds before running next function in JAVA FXML (using SCENEBUILDER)

dstar19

I've used Scenebuilder to place few shapes in my GUI (simplified version of my project). I would like the shapes to change colours but wait 2 seconds between changing colours. I want these changes to happen in my controller class after a button is pressed.

Circle1.setFill(YELLOW)
Wait(2 seconds)
Circle2.setFill(BLUE)

I'm not sure how to do that. I have read online about threading, but I don't really understand how to implement that from my Main and into my Controller class. Also, I could not really find any examples online. My Main class looks like:

public class Main extends Application {
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        BorderPane root = (BorderPane)FXMLLoader.load(getClass().getResource("File.fxml"));
        Scene scene = new Scene(root);
        scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
        primaryStage.setScene(scene);
        primaryStage.show();    
    }
}

Please help. Also, if you could provide an example would be helpful for me to understand as I could not really find one online that gives an example of this.

d.j.brown

Answering this question is easiest through an example I believe. So I've created a small Traffic Light application, since it allows me to use Circle and a timed sequence similar to your problem, whilst being a familiar concept for all.

I'll be using java.util.Timer alongside java.util.TimerTask for handling the sequence of lights. You may choose to use some animation / time line in JavaFX, but I think that is overkill for this kind of task.

I include the three files used in this project:

  • FXMLTrafficLight.fxml - which defines my FXML layout
  • FXMLTrafficLightController.java - my FXML controller
  • TrafficLightApplication.java - for completeness my subclass of Application, this is just the boiler plate.

FXMLTrafficLight.fxml

Not a fancy layout, just a VBox with three circles redLight, amberLight and greenLight, plus two Button objects startLights and stopLights used to start and stop the timer.

<VBox fx:id="root" id="VBox" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javafxtimer.FXMLTrafficLightController">
    <children>
        <Circle fx:id="redLight" radius="100"></Circle>
        <Circle fx:id="amberLight" radius="100"></Circle>
        <Circle fx:id="greenLight" radius="100"></Circle>
        <Button fx:id="startLights" text="Start Lights" onAction="#startLights"></Button>
        <Button fx:id="stopLights" text="Start Lights" onAction="#stopLights"></Button>
    </children>
</VBox>

FXMLTrafficLightController.java

I've included the model/state in the controller for simplicity. Whether a light is red / amber / green is determined by a boolean flag. The initial state is set in the initialize() method, and is updated by calling updateState().

When startLights(ActionEvent) is invoked (the EventHandler for startLights) a new Timer is constructed with a TimerTask implementation that first invokes updateState() on the thread created by the Timer and then invokes updateLights() which changes the color of the lights based on the current state on the JavaFX Application Thread using Platform.runLater(Runnable).

Note: the TimerTask itself will not be run on the JavaFX Application Thread, hence the need to use Platform.runLater(Runnable) for updating the GUI.

When stopLights(ActionEvent) is invoked, it will cancel the Timer.

Note that both startLights(ActionEvent) and stopLights(ActionEvent) toggle which Button objects are enabled on the interface as well.

public class FXMLTrafficLightController implements Initializable {

    @FXML
    private Circle redLight;

    @FXML
    private Circle amberLight;

    @FXML
    private Circle greenLight;

    @FXML
    private Button startLights;

    @FXML
    private Button stopLights;

    private Timer timer;
    private static final int DELAY = 2000; // ms

    private boolean red, amber, green;

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        red = true;
        amber = false;
        green = false;
        stopLights.setDisable(true);
        updateLights();
    }

    @FXML
    private void startLights(ActionEvent e) {
        toggleButtons();
        timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                // Not run on the JavaFX Application Thread!
                updateState();
                // Using Platform.runLater(Runnable) to ensure updateLights()
                // is run on the JavaFX Application Thread
                Platform.runLater(new Runnable() {
                    @Override
                    public void run() {
                        updateLights();
                    }
                });
            }
        }, 0, DELAY); // no initial delay, trigger again every 2000 ms (DELAY)
    }

    @FXML
    private void stopLights(ActionEvent e) {
        toggleButtons();
        timer.cancel();        
    }

    private void toggleButtons() {        
        startLights.setDisable(!startLights.isDisable());
        stopLights.setDisable(!stopLights.isDisable());
    }

    private void updateState() {
        if (red && !amber && !green) {
            amber = true;
        } else if (red && amber && !green) {
            red = false;
            amber = false;
            green = true;
        } else if (!red && !amber && green) {
            green = false;
            amber = true;
        } else {
            red = true;
            amber = false;
            green = false;
        }
    }

    private void updateLights() {
        redLight.setFill(red ? Color.RED : Color.GREY);
        amberLight.setFill(amber ? Color.ORANGE : Color.GREY);
        greenLight.setFill(green ? Color.GREEN : Color.GREY);
    }
}

TrafficLightApplication.java

For completeness... Just the standard boiler plate with file names changed.

public class TrafficLightApplication extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("FXMLTrafficLight.fxml"));        
        Scene scene = new Scene(root);        
        stage.setScene(scene);
        stage.show();
    }

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

}

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

Sleep for x seconds before running next operation

setting timeout for async function to stop running after x seconds if not done by then

How to wait for x seconds before clicking the next button using Javascript

Sleep 3 seconds before sending out next request using CURL

JavaFX: Align Buttons inside ButtonBar (using SceneBuilder or fxml)

Running code every x seconds using map from database

Running a request in background every x seconds using Locust

How to make code wait x seconds before executing next iteration of loop in JS/ JQUery?

If no activity for X seconds, run function that toggles classname. If activity, stop toggle function and reset inactivity timer

Switching scenes the FXML way (SceneBuilder)

Android/Java - Wait for AsyncTask to end before performing next function

function running before call

Is learning JavaFX before using FXML neccessary?

Stop recording after silence of X seconds

Java FX with scenebuilder: Exception running application Start.Main

Execute an instruction every x seconds in a for loop of an arraylist using JAVA

How to stop calling next() on a generator before StopIteration

Waiting for a sound to stop before playing the next sound

How to Stop a Running a Program Using Other Java Program

How to stop a function after ten seconds?

Stop JavaScript function after 3 seconds

Processing: How can i make a function wait before running the next line?

Call a function before jetty stop

Javascript + Run a function for X seconds

Call a function every X seconds

Run a Python function for x seconds?

Can not stop the function running on setTimeout

Stop and resume a running function on javascript

jQuery stop function running twice