model.gui.PlayButton.java Source code

Java tutorial

Introduction

Here is the source code for model.gui.PlayButton.java

Source

/*
 * Copyright (c) 2014 by Ernesto Carrella
 * Licensed under MIT license. Basically do what you want with it but cite me and don't sue me. Which is just politeness, really.
 * See the file "LICENSE" for more information
 */

package model.gui;

import com.google.common.base.Preconditions;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.Button;
import model.MacroII;

import java.util.concurrent.Semaphore;

/**
 * This small presentation is very important in the sense that it holds the main model thread.
 * The model thread can be paused/restarted at the end of each step through the use of a simple binary semaphore.
 * It's a button and its own listener
 * Created by carrknight on 4/11/14.
 */
public class PlayButton extends Button implements EventHandler<ActionEvent> {

    private final Semaphore playPauseSemaphore;

    public PlayButton(MacroII modelToRun) {
        super("Play");
        Preconditions.checkState(modelToRun.hasStarted(), "need to have started before this is spawned!");

        //create the pause metaphore
        playPauseSemaphore = new Semaphore(0);

        //create the thread running the simulation
        Thread modelThread = new Thread(() -> {
            try {
                //this trick I found by asking on :
                // http://stackoverflow.com/questions/23017888/boolean-semaphore-in-java/23018659?noredirect=1#23018659
                playPauseSemaphore.acquire(); // Block if paused
                playPauseSemaphore.release();
                while (true) {
                    //step the model
                    modelToRun.schedule.step(modelToRun);
                    playPauseSemaphore.acquire(); // Block if paused
                    playPauseSemaphore.release();
                }
            } catch (InterruptedException ignored) {
                System.err.println("interrupted");
            }
        });
        modelThread.setName("Simulation Thread");
        modelThread.setDaemon(true); //close with the simulation

        //you can start it immediately, it will immediately pause
        modelThread.start();

        this.setPrefSize(200, 40);
        this.addEventHandler(javafx.event.ActionEvent.ACTION, this);

    }

    @Override
    public void handle(ActionEvent actionEvent) {
        assert Platform.isFxApplicationThread(); //just making sure here
        //to avoid mistakes with "this" in the runnables, let me copy a reference to myself
        PlayButton play = this;

        //you pressed the button. If it was "play"
        if (play.getText().equals("Play")) {
            //change your text to "Pause"
            play.setText("Pause");
            //start the engine!
            playPauseSemaphore.release();

        } else {
            //if it wasn't play, it was pause!
            Preconditions.checkState(play.getText().equals("Pause"));
            play.setDisable(true); //grey it out until the pause takes effect!
            play.setText("Pausing...");
            //spawn a simple thread to stop the model and then reset the button!
            Thread pausingThread = new Thread(() -> {
                try {
                    playPauseSemaphore.acquire();
                    Preconditions.checkState(playPauseSemaphore.availablePermits() == 0);
                    //fix the button
                    Platform.runLater(() -> { //to be done in the JAVAFX thread
                        play.setText("Play");
                        play.setDisable(false);
                    });
                } catch (Exception ignored) {
                    System.err.println("Failed to unpause!");
                }
            });
            pausingThread.setDaemon(true);
            pausingThread.start(); //go pause

        }

    }
}