Javafx启动 - 停止重启UI

时间:2014-07-14 15:39:45

标签: javafx

程序Triathlon执行长时间运行的任务,如果任务已完全执行,可以再次重新启动它。我想添加停止执行以重置UI的可能性。为此,我添加了一个新按钮,停止。这是代码:

package triathlon2;

import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javafx.animation.FadeTransition;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.*;
import javafx.beans.property.*;
import javafx.beans.value.*;
import javafx.concurrent.Task;
import javafx.event.*;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.*;
import javafx.stage.Stage;
import javafx.util.Duration;

public class Triathlon2 extends Application 
{

  private final Random random = new Random();
  private final ExecutorService exec = Executors.newSingleThreadExecutor();
  final TaskMonitor taskMonitor = new TaskMonitor();

    final ProgressIndicator progressIndicator 
            = new ProgressIndicator();


  @Override public void start(Stage stage) throws Exception 
  {
    progressIndicator.progressProperty()
            .bind(taskMonitor.currentTaskProgressProperty());

    final Label currentRaceStage = new Label();
    currentRaceStage.textProperty()
            .bind(taskMonitor.currentTaskNameProperty());

    createMainLayout(
        stage,
        createStartRaceButton(
            exec,
            taskMonitor
        ),
        createStopButton(
            //exec,
            taskMonitor
        ),
        createRaceProgressView(
            taskMonitor,
            progressIndicator,
            currentRaceStage
        )
    );
  }



  @Override public void stop() throws Exception 
  {
    exec.shutdownNow();
  }



  private Button createStartRaceButton(
          final ExecutorService exec, 
          final TaskMonitor taskMonitor) 
  {
    final Button startButton = new Button("Start Race");
    startButton.disableProperty()
            .bind(taskMonitor.idleProperty().not());
    startButton.setOnAction((ActionEvent actionEvent) -> 
    {
        runRace(exec, taskMonitor);

    });
    return startButton;
  }

    private Button createStopButton(
          //final ExecutorService exec, 
          final TaskMonitor taskMonitor) 
  {
    final Button stopButton = new Button("Stop Race");

    stopButton.disableProperty()
            .bind(taskMonitor.idleProperty());

    stopButton.setOnAction((ActionEvent actionEvent) -> 
    {
        exec.shutdownNow(); 

        Platform.setImplicitExit(true);

    });
    return stopButton;
  }

  private HBox createRaceProgressView(
          final TaskMonitor taskMonitor, 
          ProgressIndicator progressIndicator, 
          Label currentRaceStage) 
  {
    final HBox raceProgress = new HBox(10);
    raceProgress.getChildren().setAll(
      currentRaceStage,
      progressIndicator
    );
    raceProgress.setOpacity(0);
    raceProgress.setAlignment(Pos.CENTER);

    final FadeTransition fade 
            = new FadeTransition(
                    Duration.seconds(0.75), raceProgress);
    fade.setToValue(0);

    taskMonitor.idleProperty()
            .addListener((Observable observable) -> 
            {
                if (taskMonitor.idleProperty().get()) 
                {
                fade.playFromStart();
                } else 
                {
                    fade.stop();
                    raceProgress.setOpacity(1);
                }
            });

    return raceProgress;
  }

  private void createMainLayout(Stage stage, Button startButton, Button stopButton, HBox raceProgress) 
  {
    final VBox layout = new VBox(10);
    layout.getChildren().setAll(
      raceProgress,
      startButton,stopButton
    );
    layout.setAlignment(Pos.CENTER);
    layout.setStyle("-fx-background-color: cornsilk; -fx-padding: 10px;");
    stage.setScene(new Scene(layout, 500, 600));
    stage.show();
  }



  private void runRace(ExecutorService exec, TaskMonitor taskMonitor) 
  {
    StageTask swimTask = new StageTask("Swim", 30,   40);
    StageTask bikeTask = new StageTask("Bike", 210, 230);
    StageTask runTask  = new StageTask("Run",  120, 140);

    taskMonitor.monitor(swimTask, bikeTask, runTask);

    exec.execute(swimTask);
    exec.execute(bikeTask);
    exec.execute(runTask);
  }



  class TaskMonitor {
    final private ReadOnlyObjectWrapper<StageTask> currentTask = new ReadOnlyObjectWrapper<>();
    final private ReadOnlyStringWrapper currentTaskName        = new ReadOnlyStringWrapper();
    final private ReadOnlyDoubleWrapper currentTaskProgress    = new ReadOnlyDoubleWrapper();
    final private ReadOnlyBooleanWrapper idle                  = new ReadOnlyBooleanWrapper(true);

    public void monitor(final StageTask task) 
    {
      task.stateProperty().addListener(new ChangeListener<Task.State>() 
      {
        @Override
        public void changed(ObservableValue<? extends Task.State> observableValue, Task.State oldState, Task.State state) 
        {
          switch (state) 
          {
            case RUNNING:
              currentTask.set(task);
              currentTaskProgress.unbind();
              currentTaskProgress.set(task.progressProperty().get());
              currentTaskProgress.bind(task.progressProperty());
              currentTaskName.set(task.nameProperty().get());
              idle.set(false);
              break;

            case SUCCEEDED:
            case CANCELLED:
            case FAILED:
              task.stateProperty().removeListener(this);
              idle.set(true);
              break;
          }
        }
      });
    }

    public void monitor(final StageTask... tasks) 
    {
      for (StageTask task: tasks) {
        monitor(task);
      }
    }


    public ReadOnlyObjectProperty<StageTask> currentTaskProperty() 
    {
      return currentTask.getReadOnlyProperty();
    }


    public ReadOnlyStringProperty currentTaskNameProperty() 
    {
      return currentTaskName.getReadOnlyProperty();
    }


    public ReadOnlyDoubleProperty currentTaskProgressProperty() 
    {
      return currentTaskProgress.getReadOnlyProperty();
    }


    public ReadOnlyBooleanProperty idleProperty() 
    {
      return idle.getReadOnlyProperty();
    }
  }



  class StageTask extends Task<Duration> 
  {
    final private ReadOnlyStringWrapper name;
    final private int minMinutesElapsed;
    final private int maxMinutesElapsed;

    public StageTask(String name, int minMinutesElapsed, int maxMinutesElapsed) 
    {
      this.name = new ReadOnlyStringWrapper(name);
      this.minMinutesElapsed = minMinutesElapsed;
      this.maxMinutesElapsed = maxMinutesElapsed;
    }

    @Override protected Duration call() throws Exception 
    {
      Duration duration = timeInRange(
        minMinutesElapsed, maxMinutesElapsed
      );

      for (int i = 0; i < 25; i++) 
      {
        updateProgress(i, 25);
        Thread.sleep((int) (duration.toMinutes()));
      }
      updateProgress(25, 25);

      return duration;
    }


    private Duration timeInRange(int min, int max) 
    {
      return Duration.minutes(
        random.nextDouble() * (max - min) + min
      );
    }


    public ReadOnlyStringProperty nameProperty() 
    {
      return name.getReadOnlyProperty();
    }
  }


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

如果任务已完成,程序将重新启动,但如果在停止后调用start,则程序将崩溃。我该怎么说?

1 个答案:

答案 0 :(得分:0)

您在此处遇到的基本逻辑错误是您尝试在Executor上启动Shutdown后向其提交任务。来自Java doc

  

启动以前提交的任务的有序关闭   已执行,但不会接受任何新任务

我们在点击shutdownNow()按钮时为exec调用了Stop Race方法。在此之后,exec无法接受任何进一步的任务。

P.S。由于您的exec是最终版,因此您无法重新实例化它!