Диалоги и Alert
Диалог — маленькое окно, которое задаёт вопрос или сообщает о чём-то важном и ждёт ответа. В JavaFX готовые диалоги лежат в javafx.scene.control: Alert для сообщений и подтверждений, TextInputDialog для ввода строки, ChoiceDialog для выбора из списка. В записной книжке диалоги предупредят о пустом заголовке, переспросят перед удалением и помогут добавить новую категорию.
Предупреждение
Кнопка «Добавить» уже отключена для пустого поля, но заголовок из одних пробелов она пропускает. Покажем предупреждение:
// src/main/java/com/example/notes/MainController.java — начало addNote()
String title = titleField.getText().strip();
if (title.isEmpty()) {
Alert alert = new Alert(Alert.AlertType.WARNING, "Заголовок не может состоять из одних пробелов.");
alert.initOwner(table.getScene().getWindow());
alert.setTitle("Заметки");
alert.setHeaderText("Пустой заголовок");
alert.showAndWait();
return;
}Дальше в addNote вместо titleField.getText().strip() используется готовая переменная title. Метод showAndWait() показывает окно и ждёт, пока его закроют; остальное окно приложения в это время не реагирует. initOwner привязывает диалог к главному окну: он появится по центру над ним и возьмёт его стили CSS — кнопки диалога будут синими. Без setTitle и setHeaderText в заголовке будет английское «Warning».
Тип AlertType | Значок | Кнопки |
|---|---|---|
INFORMATION | i | OK |
WARNING | ! | OK |
ERROR | красный крест | OK |
CONFIRMATION | ? | OK, Cancel |
NONE | нет | только переданные |
Подтверждение
showAndWait() возвращает Optional с нажатой кнопкой. Если окно закрыли крестиком, внутри будет кнопка отмены:
// src/main/java/com/example/notes/MainController.java — фрагмент deleteNote()
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.initOwner(table.getScene().getWindow());
alert.setTitle("Удаление");
alert.setHeaderText("Удалить заметку «" + notes.get(index).title() + "»?");
alert.setContentText("Отменить это действие будет нельзя.");
alert.showAndWait()
.filter(button -> button == ButtonType.OK)
.ifPresent(button -> notes.remove(index));Стандартные кнопки подписаны по-английски: OK и Cancel — русского перевода в JavaFX нет.
Свои кнопки
Кнопки можно создать самим и передать в конструктор Alert. Роль кнопки задаёт ButtonData: OK_DONE — основное действие, CANCEL_CLOSE — отмена, ей же считается закрытие крестиком и клавиша Esc:
// src/main/java/com/example/notes/MainController.java — метод deleteNote()
@FXML
private void deleteNote() {
int index = table.getSelectionModel().getSelectedIndex();
if (index < 0) {
return;
}
ButtonType delete = new ButtonType("Удалить", ButtonBar.ButtonData.OK_DONE);
ButtonType cancel = new ButtonType("Отмена", ButtonBar.ButtonData.CANCEL_CLOSE);
Alert alert = new Alert(Alert.AlertType.CONFIRMATION,
"Отменить это действие будет нельзя.", delete, cancel);
alert.initOwner(table.getScene().getWindow());
alert.setTitle("Удаление");
alert.setHeaderText("Удалить заметку «" + notes.get(index).title() + "»?");
alert.showAndWait()
.filter(button -> button == delete)
.ifPresent(button -> notes.remove(index));
}Выделите заметку и нажмите «Удалить». Появится окно «Удаление» со знаком вопроса, вопросом «Удалить заметку «Купить молоко»?», строкой «Отменить это действие будет нельзя.» и кнопками «Удалить» и «Отмена». Заметка исчезнет только после «Удалить».
Ввод строки
Рядом со списком категорий поставим кнопку «Новая...»:
<!-- src/main/resources/com/example/notes/main-view.fxml — вместо строки с ComboBox -->
<HBox spacing="8" GridPane.rowIndex="2" GridPane.columnIndex="1">
<ComboBox fx:id="categoryBox"/>
<Button text="Новая..." onAction="#addCategory"/>
</HBox>TextInputDialog возвращает Optional с введённой строкой:
// src/main/java/com/example/notes/MainController.java — новый метод addCategory()
@FXML
private void addCategory() {
TextInputDialog dialog = new TextInputDialog();
dialog.initOwner(table.getScene().getWindow());
dialog.setTitle("Новая категория");
dialog.setHeaderText("Введите название категории");
dialog.showAndWait()
.map(String::strip)
.filter(name -> !name.isEmpty())
.ifPresent(name -> {
categoryBox.getItems().add(name);
categoryBox.setValue(name);
});
}Введите «Учёба» и нажмите OK — категория появится в списке и сразу станет выбранной. После Cancel Optional пуст, и ничего не происходит.
Частая ошибка
После замены стандартных кнопок на свои забывают поправить проверку и оставляют button == ButtonType.OK. Теперь нажатая кнопка — это объект delete, сравнение никогда не даёт true, и заметка не удаляется. Ошибки нет, просто ничего не происходит. Сравнивайте с той кнопкой, которую передали в Alert.