3.5.1.1.3. События Screen

Ниже описаны события жизненного цикла экрана, на которые можно подписаться в контроллере для реализации необходимой бизнес-логики.

Руководство Decouple Business Logic with Application Events содержит примеры использования событий в UI.



InitEvent

InitEvent посылается, когда контроллер экрана и все его компоненты, заданные декларативно, созданы, а инжекция зависимостей завершена. Вложенные фрагменты на этом этапе ещё не инициализированы. Некоторые визуальные компоненты инициализированы не полностью: например, кнопки ещё не связаны с действиями.

@Subscribe
protected void onInit(InitEvent event) {
    Label<String> label = uiComponents.create(Label.TYPE_STRING);
    label.setValue("Hello World");
    getWindow().add(label);
}
AfterInitEvent

AfterInitEvent посылается, когда контроллер экрана и все его компоненты, заданные декларативно, созданы, инжекция зависимостей завершена, и все компоненты завершили свою внутреннюю процедуру инициализации. Вложенные фрагменты (при наличии) опубликовали свои события InitEvent и AfterInitEvent. В слушателе этого события можно создавать визуальные компоненты и компоненты данных, а также выполнить дополнительную инициализацию, если она зависит от инициализации вложенных фрагментов.

InitEntityEvent

InitEntityEvent посылается в экранах, унаследованных от StandardEditor и MasterDetailScreen, перед тем, как новый экземпляр сущности будет установлен для контейнера редактируемой сущности.

Руководство Initial Entity Values содержит пример инициализации сущности с помощью InitEntityEvent.

Используйте слушатель этого события, чтобы инициализировать значения по умолчанию для новых экземпляров сущностей, например:

@Subscribe
protected void onInitEntity(InitEntityEvent<Foo> event) {
    event.getEntity().setStatus(Status.ACTIVE);
}
BeforeShowEvent

BeforeShowEvent посылается непосредственно перед тем, как экран будет отображён, иными словами, на этом этапе он ещё не добавлен к интерфейсу приложения. Ограничения безопасности уже применены к компонентам UI. Сохранённые настройки состояния компонентов UI ещё не применены. Данные ещё не загружены в экраны с аннотацией @LoadDataBeforeShow. В слушателе этого события можно загружать данные, проверять разрешения безопасности, а также изменять компоненты интерфейса. Например:

@Subscribe
protected void onBeforeShow(BeforeShowEvent event) {
    customersDl.load();
}
AfterShowEvent
  • AfterShowEvent посылается сразу после отображения экрана, то есть тогда, когда экран уже добавлен к интерфейсу приложения. На этом этапе применены сохранённые настройки состояния компонентов UI. В слушателе этого события можно отображать уведомления, диалоговые окна или другие экраны. Например:

@Subscribe
protected void onAfterShow(AfterShowEvent event) {
    notifications.create().withCaption("Just opened").show();
}
BeforeCommitChangesEvent

BeforeCommitChangesEvent посылается в экранах, унаследованных от StandardEditor и MasterDetailScreen, перед сохранением измененных данных методом commitChanges(). В слушателе этого события можно проверить какие-либо условия и прервать или продолжить операцию сохранения с помощью методов preventCommit() и resume() объекта события.

Рассмотрим некоторые варианты использования.

  1. Прервать операцию сохранения с выводом уведомления:

    @Subscribe
    public void onBeforeCommitChanges(BeforeCommitChangesEvent event) {
        if (getEditedEntity().getStatus() == null) {
            notifications.create().withCaption("Enter status!").show();
            event.preventCommit();
        }
    }
  2. Прервать операцию сохранения, показать диалог и продолжить после подтверждения пользователем:

    @Subscribe
    public void onBeforeCommitChanges(BeforeCommitChangesEvent event) {
        if (getEditedEntity().getStatus() == null) {
            dialogs.createOptionDialog()
                    .withCaption("Confirmation")
                    .withMessage("Status is empty. Do you really want to commit?")
                    .withActions(
                            new DialogAction(DialogAction.Type.OK).withHandler(e -> {
                                // resume with default behavior
                                event.resume();
                            }),
                            new DialogAction(DialogAction.Type.CANCEL)
                    )
                    .show();
            // abort
            event.preventCommit();
        }
    }
  3. Прервать операцию сохранения, показать диалог и повторить commitChanges() после подтверждения пользователем:

    @Subscribe
    public void onBeforeCommitChanges(BeforeCommitChangesEvent event) {
        if (getEditedEntity().getStatus() == null) {
            dialogs.createOptionDialog()
                    .withCaption("Confirmation")
                    .withMessage("Status is empty. Do you want to use default?")
                    .withActions(
                            new DialogAction(DialogAction.Type.OK).withHandler(e -> {
                                getEditedEntity().setStatus(getDefaultStatus());
                                // retry commit and resume action
                                event.resume(commitChanges());
                            }),
                            new DialogAction(DialogAction.Type.CANCEL)
                    )
                    .show();
            // abort
            event.preventCommit();
        }
    }
AfterCommitChangesEvent

AfterCommitChangesEvent посылается в экранах, унаследованных от StandardEditor и MasterDetailScreen, после сохранения измененных данных методом commitChanges(). Пример использования:

@Subscribe
public void onAfterCommitChanges(AfterCommitChangesEvent event) {
    notifications.create()
            .withCaption("Saved!")
            .show();
}
BeforeCloseEvent

BeforeCloseEvent посылается непосредственно перед закрытием экрана с помощью метода close(CloseAction). На этом этапе экран ещё отображается и полностью функционален. Настройки состояния компонентов ещё не сохранялись. В слушателе этого события можно проверить некоторые условия и предотвратить закрытие экрана, используя метод события preventWindowClose(), например:

@Subscribe
protected void onBeforeClose(BeforeCloseEvent event) {
    if (Strings.isNullOrEmpty(textField.getValue())) {
        notifications.create().withCaption("Input required").show();
        event.preventWindowClose();
    }
}

Одноимённый метод также определён в интерфейсе Window. Он вызывается перед тем, как экран будет закрыт неким внешним (относительно контроллера) действием, таким как нажатие кнопки во вкладке окна или клавиши Esc на клавиатуре. Способ, которым экран был закрыт, можно получить с помощью метода getCloseOrigin(), который возвращает значение в виде объекта, реализующего интерфейс CloseOrigin. Реализация этого интерфейса по умолчанию CloseOriginType включает в себя три значения:

  • BREADCRUMBS - экран закрыт по клику на цепочке ссылок (breadcrumbs).

  • CLOSE_BUTTON - экран закрыт по нажатию на кнопку закрытия в заголовке окна, на кнопку закрытия вкладки или через действия в контекстном меню: Close, Close All, Close Others.

  • SHORTCUT - экран закрыт нажатием горячих клавиш, определённых в свойстве приложения cuba.gui.closeShortcut.

Вы можете подписаться на событие Window.BeforeCloseEvent, указав Target.FRAME в аннотации @Subscribe:

@Subscribe(target = Target.FRAME)
protected void onBeforeClose(Window.BeforeCloseEvent event) {
    if (event.getCloseOrigin() == CloseOriginType.BREADCRUMBS) {
        event.preventWindowClose();
    }
}
AfterCloseEvent

AfterCloseEvent посылается после того, как экран будет закрыт методом close(CloseAction), и после события Screen.AfterDetachEvent. Настройки состояния компонентов сохранены. Слушатель этого события можно использовать для вывода уведомлений или диалоговых окон после закрытия экрана, например:

@Subscribe
protected void onAfterClose(AfterCloseEvent event) {
    notifications.create().withCaption("Just closed").show();
}
AfterDetachEvent

AfterDetachEvent посылается после того, как экран удаляется из интерфейса приложения после закрытия экрана пользователем или выхода пользователя из системы. Слушатель этого события можно использовать для освобождения ресурсов, захваченных экраном. Обратите внимание, что при истечении HTTP-сессии это событие не публикуется.

UrlParamsChangedEvent

UrlParamsChangedEvent посылается, когда изменяются параметры URL браузера, соответствующие данному экрану. Событие вызывается перед отображением экрана, что позволяет произвести некоторую подготовительную работу. В слушателе этого события можно загружать данные или изменять состояние элементов управления в экране в соответствии с новыми параметрами:

@Subscribe
protected void onUrlParamsChanged(UrlParamsChangedEvent event) {
    Map<String, String> params = event.getParams();
    // handle new params
}