Как сохранить прогресс ProgressBar после завершения задачи обслуживания? - PullRequest
0 голосов
/ 01 октября 2019

Среда: OpenJDK12, JavaFX11

Контекст: У меня есть программа, которая читает большой документ и отслеживает прочитанные байты, записывая сумму вJSON файл. При чтении файла ProgressBar обновляется, показывая процент. Еще не реализовано, когда программа запускается, ProgressBar устанавливается в соответствии с байтами, прочитанными в файле.

Проблема: Я прочитал, я не могу приостановить задачу, потому что этонаименьшая единица работы, это как разовый процесс. Поэтому, когда я «приостанавливаю» задачу с помощью service.cancel(), прогресс все еще виден. Когда я хочу возобновить чтение, я должен установить задачу в состояние READY с помощью service.reset(), но при этом прогресс теряется.

Как мне удается не потерять прогресс?

Пробовал: Я ничего не пробовал, потому что я не знаю, каков наилучший подход. Я выдвинул 2 идеи:

  1. Вместо того, чтобы наблюдать за прогрессом Task, наблюдать за прогрессом Service (возможно ли это?). Я имею в виду, что в фоновом режиме класс Service связывает свой прогресс с прогрессом Task, оба они реализуют интерфейс Worker. Итак, я подумал отсоединить Service от Task progress и реализовать свой собственный метод updateProgress ()? Возможно, это просто слишком сложная идея.

  2. Внутри createTask (), в task.setOnCancelled () получить свойства хода выполнения и каким-то образом снова установить их в ProgressBar.

В обоих случаях я не вижу, как связать свойство прогресса ProgressBar со службой, задача которой была отменена.

Любая помощь приветствуется.

Соответствующий код:

Контроллер:

public class MyController implements Initializable{
    @FXML
    private TableView<MyService> dataTable;

    @FXML
    private TableColumn<MyService, Double> progressColumn;
    @FXML
    private TableColumn<MyService,Object> actionColumn;

    private ObservableList<MyService> observableList;
    private List<MyService> serviceList;
    private MyThreadPoolExecutor threadPoolExecutor;  

    public MyController(){
      threadPoolExecutor = new MyThreadPoolExecutor();
      List<MyBean> myFileList ;//get files...

      myFileList.forEach(f->{
        serviceList.add(new MyService(f,threadPoolExecutor));
      });
      observableList = FXCollections.observableArrayList(serviceList);
    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        progressColumn.setCellValueFactory(new PropertyValueFactory<MyService,Double>("progress"));
        progressColumn.setCellFactory(ProgressCell.<Double>forTableColumn());
        actionColumn.setCellValueFactory(new PropertyValueFactory<MyService,Object> "taskAction"));
        actionColumn.setCellFactory(ActionCell.<Object>forTableColumn(this));

        dataTable.setItems(observableList);
    }

    public void startReading(MyService service) {
      service.start();  
    }
    public void pauseReading(MyService service){
      service.cancel();
      service.reset();
    }

}

Ячейка прогресса:

  public class ProgressCell extends TableCell<MyService , Double> {

    private ProgressBar bar;
    private ObservableValue<Double> observable;


    public static <S>Callback<TableColumn<MyService ,Double>,TableCell<MyService ,Double>>
    forTableColumn() {
        return param -> new ProgressCell();
    }

    @Override
    protected void updateItem(Double item, boolean empty) {

        super.updateItem(item, empty);

        if (empty || item == null) {
            setGraphic(null);
        } else {
          TableColumn<MyService , Double> column = getTableColumn();
          observable = column == null ? null : column.getCellObservableValue(getIndex());

            if (observable != null) {
                bar.progressProperty().bind(observable);
            } else if (item != null) {
                bar.setProgress(item);
            }
            setGraphic(bar);
       }

    }

}

Служба:

public class MyService extends Service<Double>{
    private SimpleObjectProperty<MyBean> file;
    private SimpleObjectProperty<Object> taskAction;

    public MyService(MyBean file, ThreadPoolExecutor executor) {
        this.file= new SimpleObjectProperty<MyBean>(file);
        super.setExecutor(executor);
    }

    @Override
    protected Task createTask() {
      try{
        MyTask task = new MyTask(this.file);
        task.setOnCancelled(event->{
          //get progress properties to save or something
        });
          return task;
      }catch(IOException e){
         e.printStacktrace();
      }
     return null;
    }

  //getters , setters & properties
}

ActionCell: имееткнопки для воспроизведения и приостановки (отмены) задания

public ActionCell extends TableCell<MyService, Object>{
    private HBox hbox;
    private Button playButton;
    private Button pauseButton;

    public ActionCell(MyController cont){
      hbox = new HBox();
      playButton= new Button();
      pauseButton= new Button();

      playButton.setOnAction(event->{ 
            MyService service = getTableView().getItems().get(getIndex());
            cont.startReading(service);
            playButton.setDisable(true);
            pauseButton.setDisable(false);
        });

      pauseButton.setOnAction(event->{
            MyService service = getTableView().getItems().get(getIndex());
            cont.pauseReading(service); 
            playButton.setDisable(false);
            pauseButton.setDisable(true);
    });
    hbox.getChildren().addAll(playButton, pauseButton);

    }

    public static <S> Callback<TableColumn<MyService, Object>, TableCell<MyService, Object>>forTableColumn(MyController cont){
        return param -> new ActionCell(cont)
    }

    @Override
    protected void updateItem(Object item, boolean empty) {
       super.updateItem(item, empty);
    if (empty || item == null) {
        setGraphic(null);
    } else {            
        setGraphic(hbox);
    }
    }
} 

1 Ответ

0 голосов
/ 03 октября 2019

Поскольку я не нашел ни полезного подхода к проектированию, ни каких-либо паузных примеров задач с несколькими Service и ThreadExecutor, я сам нашел решение. Это не идеально, но и неправильно.

Проблема была в отмене и сбросе Задачи при нажатии на паузу. Это приводит к тому, что Задача больше не существует, и рабочее состояние изменяется на ГОТОВО и, следовательно, теряет прогресс.

Решение было на reset () перед start (), только при необходимости (если Задача была отменена),Таким образом, при перезапуске Задача восстановит сам ход выполнения и снова установит его на ProgressBar.

public void startReading(MyService service) {
  //start task and reset only if needed
  if(service.getState().equals(Worker.State.CANCELLED)) {
     service.reset();
     service.start();
  }else {
     service.start();
  }

}

public void pauseReading(MyService service) {
    service.cancel();
}

Ссылки:

Запуск службы в фоновом потоке

Сервис

Рабочий

Задание

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...