Среда: OpenJDK12, JavaFX11
Контекст: У меня есть программа, которая читает большой документ и отслеживает прочитанные байты, записывая сумму вJSON файл. При чтении файла ProgressBar
обновляется, показывая процент. Еще не реализовано, когда программа запускается, ProgressBar
устанавливается в соответствии с байтами, прочитанными в файле.
Проблема: Я прочитал, я не могу приостановить задачу, потому что этонаименьшая единица работы, это как разовый процесс. Поэтому, когда я «приостанавливаю» задачу с помощью service.cancel()
, прогресс все еще виден. Когда я хочу возобновить чтение, я должен установить задачу в состояние READY
с помощью service.reset()
, но при этом прогресс теряется.
Как мне удается не потерять прогресс?
Пробовал: Я ничего не пробовал, потому что я не знаю, каков наилучший подход. Я выдвинул 2 идеи:
Вместо того, чтобы наблюдать за прогрессом Task
, наблюдать за прогрессом Service
(возможно ли это?). Я имею в виду, что в фоновом режиме класс Service
связывает свой прогресс с прогрессом Task
, оба они реализуют интерфейс Worker
. Итак, я подумал отсоединить Service от Task progress и реализовать свой собственный метод updateProgress ()? Возможно, это просто слишком сложная идея.
Внутри 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);
}
}
}