Callback — функция обратного вызова. Используется тогда, когда необходимо выполнить определенный кусок кода, передав данный кусок кода в виде параметра методу и, естественно, данный кусок будет исполняться внутри переданного метода. Чтобы передать данный кусок кода, нам необходимо это кусок кода как-то именовать, естественно, что в Java мы будет это организовать в виде метода и будем передавать этот метод в виде аргумента другим методам.
Когда и где это может быть использовано?
Для начала, рассмотрим задачу вывода диалогового окна, средствами JavaFX. Так как JavaFX не содержит в арсенале понятие диалоговое окно, то нам придется его создавать самим. Такое окно может выводить любую информацию в виде элемента управления или просто текста. Нам необходимо как-то обработать события, которые расположены на данном диалоговом окне. Для решения данной задачи, сначала, воспользуемся решением без использования callback
public class Dialog { /** Интерфейс для обработки события*/ public static String result = null;//Создадим поле хранения текущего значения public static void setResult(String result)//Реализуем setter { Dialog.result = result; } public static String getResult()//Реализуем getter { return Dialog.result; } //Метод реализации вывода диалогового окна public static void showAlert(String title){ //Создаем новый экземпляр стадии(будет выполняться наряду с основным потоком программы) final Stage dlgStage = new Stage(); //Создадим кнопку Button btnOk = new Button("Ok"); //Прикрепим к кнопке событие btnOk.setOnAction(new EventHandler(){ @Override public void handle(ActionEvent arg0) { setResult("Yo click Ok!");//Устанавливаем значение при нажатии на кнопку dlgStage.close();//Закрываем диалоговое окно при нажатии } }); //Текстовое поле для вывода информации Label lblTitle = new Label(title); lblTitle.setFont(Font.font("Amble CN", FontWeight.NORMAL, 14)); //Создаем контейнер для вертикального выравнивания элементов VBox vbox = new VBox(lblTitle,btnOk); vbox.setAlignment(Pos.CENTER); vbox.setMinSize(300, 200); //Создаем новую сцену и передаем ей контейнер Scene dlgScene = new Scene(vbox); //Устанавливаем сцену, инициализировав стили и т.д. dlgStage.setScene(dlgScene); dlgStage.initStyle(StageStyle.UNDECORATED); dlgStage.initModality(Modality.APPLICATION_MODAL); dlgStage.setMinWidth(300); dlgStage.setMinHeight(200); dlgStage.show(); } }
Наш класс реализации диалогового окна готов, настал момент вывести его на экран, написав следующий код
Dialog.showAlert("Hello world!"); if(Dialog.getResult() != null) { System.out.println(Dialog.getResult());// Результат, записанный при нажатии }
В результате мы получим следующий результат на экране
Нажмем на кнопку и посмотрим на вывод в консоле NetBeans, где у нас ничего не выведется в первый раз, потому что диалоговое окно выполняется своим потоком, а программа своим и после нажатия на «ok» мы инициализируем значение поля result, закрываем диалоговое окно, но повторно — то этот код не выпонится, поэтому значение в result при первом запуске будет null, как мы его инициализировали в классе Dialog. При повторном выполнении данного кода у нас выведется тоже самое окно, но значение уже будет не текущее, а предыдущего нажатия, что не есть нормально, так как создается 2 потока: 1- поток программы, 2 — поток диалогового окна.
Решение проблемы с помощью callback
Код ниже именуется как callback
.
new EventHandler<ActionEvent>(){ @Override public void handle(ActionEvent arg0){ dlgStage.close(); } }
Callback не возвращает type, как вы можете видеть выше в примере, он void
.
Callback — и имеют методы, которые вы получаете как аргументы в другом методе. Другой метод должен вызвать callback метод, когда он пожелает. Это значит, что callback — и имеют асинхронность.
В вашем примере, он вызывает callback, когда вы жмете на кнопку.
И в заключении, вы не сможете возвратить его, используя return.
Что делать ?
Вы можете вызвать метод из вашего callback и отправить ваше возвращаемое значение ему как аргумент.
Пример:
btnCancel.setOnAction( newEventHandler<ActionEvent>(){ @Override public void handle(ActionEvent arg0){ YourClass.setReturnValue("This is button Cancel"); dlgStage.close(); } });
Где setReturnValue -метод принадлежащий вашему классу YourClass или его экземпляр, который будет содержать ваше возвращаемое значение.
Другой и лучшим путем подхода будет создание класса, который будет наследовать Stage. Также в вашем showPrompt методе вы должны блокировать выполнение основного потока, используя showAndWait() или похожим образом.
В заключении, вы не можете создавать весь Prompt из только одного метода.