Вопрос или проблема
Я разрабатываю небольшое настольное приложение на JavFXML, которое включает в себя TaskWorker. Цель заключается в том, чтобы запустить task worker при нажатии на кнопку, но ничего не происходит, и task worker не вызывается. Код обработки клика мыши выглядит так:
public class TableViewController implements Initializable{
....
@FXML private void handleGoButton () {
TaskWorker taskworker = new TaskWorker(50);
new Thread(taskworker).start();
}
Изначальная цель заключалась в том, чтобы запустить индикатор прогресса и операции копирования файлов внутри task worker, но чтобы попытаться понять проблему, я убрал большую часть этого кода и заменил его простым циклом, который выводит значение индекса. Таким образом, task worker выглядит так:
public class TaskWorker extends Task<Void> {
public int value;
public TaskWorker (int value) {
this.value = value;
System.out.println("Value = " + this.value );
}
@Override
protected Void call() throws Exception {
int pind = 1;
String bkpdate = new ValiDate().gettodaysSwedishDate();
for (int i=0; i < this.value; i++){
System.out.println("Value of i = " + i );
Thread.sleep(400);
}
return null;
}
}
При нажатии мыши я ожидал увидеть вывод, подтверждающий, что конструктор в TaskWorker получил переданное значение, и вывод, показывающий значение индекса до переданного значения. Task worker действительно получает значение в конструкторе:
compile:
run:
Value = 50
BUILD SUCCESSFUL (total time: 18 seconds)
но метод call()
никогда не запускается.
Ответ или решение
Судя по вашему описанию, проблема заключается в том, что вы пытаетесь запустить задачу TaskWorker
, создавая новый поток непосредственно из метода обработки нажатия кнопки. В JavaFX все обновления пользовательского интерфейса должны выполняться в его основном потоке (говне. thread safe), и запуск задач в отдельных потоках, как в вашем случае, может вызвать проблемы.
Правильный способ запуска Task
в JavaFX – это использовать встроенные механизмы, которые уже работают с потоками, такие как Task
и Service
. Вместо создания нового потока для выполнения задачи, следует использовать сам объект Task
для выполнения асинхронной работы.
Ниже приводится исправленный вариант вашего кода, который должен решить вашу проблему. Здесь я улучшил реализацию с использованием Task
и показал, как можно правильно запускать задачу:
public class TableViewController implements Initializable {
@FXML
private ProgressIndicator progressIndicator; // Для отображения индикатора прогресса
@FXML
private Button goButton; // Кнопка для запуска задачи
@FXML
private void handleGoButton() {
TaskWorker taskWorker = new TaskWorker(50);
// Указываем, что обновления состояния задачи будут обрабатываться здесь
taskWorker.setOnSucceeded(e -> {
System.out.println("Задача завершена успешно!");
progressIndicator.setVisible(false); // Скрыть индикатор прогресса
});
taskWorker.setOnFailed(e -> {
System.out.println("Задача завершилась с ошибкой!");
progressIndicator.setVisible(false); // Скрыть индикатор прогресса
});
taskWorker.setOnRunning(e -> {
progressIndicator.setVisible(true); // Показать индикатор прогресса
});
// Запускаем задачу на новом потоке
new Thread(taskWorker).start();
}
}
public class TaskWorker extends Task<Void> {
public int value;
public TaskWorker(int value) {
this.value = value;
System.out.println("Value = " + this.value);
}
@Override
protected Void call() throws Exception {
for (int i = 0; i < this.value; i++) {
System.out.println("Value of i = " + i);
Thread.sleep(400); // Эмуляция длительной работы
updateProgress(i + 1, this.value); // Обновление прогресса (если нужно)
}
return null; // Успешное завершение
}
}
Основные изменения:
-
Использование методов
setOnSucceeded
,setOnFailed
иsetOnRunning
: Эти методы обеспечивают обработку событий, связанных с состоянием задачи, позволяя вам управлять прогрессом и выводить сообщения, когда задача выполнена или завершилась с ошибкой. -
Индикатор прогресса: Добавьте
ProgressIndicator
в ваш интерфейс, чтобы пользователь видел, что процесс выполняется. В коде я добавил управление его видимостью. -
Обновление прогресса: Вы можете обновлять прогресс выполнения задачи с помощью
updateProgress()
, что позволит вашему интерфейсу отображать соответствующий прогресс.
После внесения этих изменений ваша задача должна корректно запускаться, а вывод в консоль должен отображаться по мере выполнения цикла в call()
.