Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Диалоги и 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ЗначокКнопки
INFORMATIONiOK
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.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.