Экран может быть открыт из главного меню, навигацией к URL, или программно из другого экрана. В данном разделе мы рассмотрим, как открывать экраны программно.
- Интерфейс Screens
-
Интерфейс
Screens
позволяет создавать и отображать экраны всех типов.Предположим, у нас есть экран для демонстрации сообщения с особым форматированием:
Контроллер экранаlink:../../../../../source/gui/screens/screens_1.java[role=include]
-
- параметр экрана
XML-дескриптор экранаlink:../../../../../source/gui/screens/screens_1.xml[role=include]
В этом случае мы можем создать и открыть его из другого экрана следующим образом:
link:../../../../../source/gui/screens/screens_2.java[role=include]
Обратите внимание, что мы сначала создаём экземпляр экрана, передаём в него параметр, а затем отображаем экран.
Если экран не требует передачи параметров из вызывающего кода, его можно создать и открыть одной строкой:
link:../../../../../source/gui/screens/screens_3.java[role=include]
WarningScreens
не является Spring-бином, поэтому его можно только инжектировать в контроллер экрана или получить его с помощью статического методаComponentsHelper.getScreenContext(component).getScreens()
. -
- Бин ScreenBuilders
-
Бин
ScreenBuilders
позволяет открывать все типы экранов с различными параметрами. Ниже приведён пример вызова экрана и выполнения некоторого кода после того, как экран закрывается (более подробно см. здесь):link:../../../../../source/gui/screens/screenBuilders_withAfterCloseListener.java[role=include]
Далее мы рассмотрим работу с экранами редактирования и выбора сущностей.
Пример открытия редактора по умолчанию для сущности
Customer
:link:../../../../../source/gui/screens/screenBuilders_editor.java[role=include]
В данном примере редактор изменит экземпляр сущности
Customer
, но вызывающий экран не получит назад обновлённую сущность.Часто требуется отредактировать сущность, отображаемую, к примеру, компонентом
Table
илиDataGrid
. В этом случае следует использовать другую форму вызова редактора, она короче и позволяет автоматически обновить исходный экземпляр в таблице:link:../../../../../source/gui/screens/screenBuilders_editor_2.java[role=include]
Чтобы создать новый экземпляр сущности и открыть экран его редактирования, достаточно вызвать метод
newEntity()
builder’а:link:../../../../../source/gui/screens/screenBuilders_editor_3.java[role=include]
TipРедактор сущности по умолчанию определяется по следующей схеме:
-
Если существует экран редактирования с аннотацией @PrimaryEditorScreen, будет использован он.
-
Если такого экрана нет, будет использован экран с идентификатором вида
{entity_name}.edit
(например,sales_Customer.edit
).
Builder предоставляет множество методов для передачи дополнительных параметров в открываемый экран. К примеру, следующий код создаёт сущность, сначала инициализируя новый экземпляр, в конкретном экране редактирования, открываемом в режиме диалогового окна:
link:../../../../../source/gui/screens/screenBuilders_editor_4.java[role=include]
Экраны выбора сущностей также можно открывать с различными параметрами.
Пример открытия экрана выбора по умолчанию для сущности
User
:link:../../../../../source/gui/screens/screenBuilders_lookup.java[role=include]
Если нужно установить выбранную сущность в качестве значения поля, используйте краткую форму вызова:
link:../../../../../source/gui/screens/screenBuilders_lookup_2.java[role=include]
TipЭкран выбора сущности по умолчанию определяется по следующей схеме:
-
Если существует экран выбора с аннотацией @PrimaryLookupScreen, будет использован он.
-
Если такого экрана нет, будет использован экран с идентификатором вида
{entity_name}.lookup
(например,sales_Customer.lookup
). -
Если и такого экрана нет, будет использован экран с идентификатором вида
{entity_name}.browse
(например,sales_Customer.browse
).
Как и в случае с экранами редактирования, вы можете использовать методы builder’а для передачи дополнительных параметров в открываемые экраны. Например, следующий код поможет выбрать сущность
User
в конкретном экране выбора, открываемом в режиме диалогового окна:link:../../../../../source/gui/screens/screenBuilders_lookup_3.java[role=include]
-
- Передача параметров в экраны
-
Рекомендуемый способ передачи параметров в открываемый экран - использование публичных setter-методов контроллера, как продемонстрировано в примере выше.
С помощью такого подхода можно передавать параметры в экраны любого типа, в том числе экраны редактирования и выбора сущностей, открываемые через ScreenBuilders или из главного меню. Пример вызова того же самого экрана
FancyMessageScreen
с передачей параметра и использованиемScreenBuilders
:link:../../../../../source/gui/screens/passing_parameters_1.java[role=include]
Другой способ - определить специальный класс для параметров и передавать экземпляр этого класса в стандартный метод
withOptions()
билдера. Класс параметров должен реализовывать маркер-интерфейсScreenOptions
. Например:link:../../../../../source/gui/screens/passing_options_1.java[role=include]
В открываемом экране
FancyMessageScreen
, объект параметров может быть получен в обработчиках InitEvent и AfterInitEvent:link:../../../../../source/gui/screens/passing_options_2.java[role=include]
Пример вызова экрана
FancyMessageScreen
черезScreenBuilders
с передачейScreenOptions
:link:../../../../../source/gui/screens/passing_options_3.java[role=include]
Как видите, данный подход требует приведения типов в контроллере, получающем параметры, поэтому используйте его только когда это необходимо и предпочитайте type-safe подход с setter-методами, описанный выше.
Использование объекта
ScreenOptions
является единственным способом получения параметров, если экран открывается из другого экрана, основанного на устаревшем API. В этом случае, объект параметров имеет типMapScreenOptions
и может быть обработан следующим образом:link:../../../../../source/gui/screens/passing_options_4.java[role=include]
- Выполнение кода после закрытия и возврат значений
-
Каждый экран посылает событие
AfterCloseEvent
после своего закрытия. Экрану можно добавить слушатель для нотификации об этом событии, например:link:../../../../../source/gui/screens/return_values_1.java[role=include]
При использовании
ScreenBuilders
, слушатель можно передать в методеwithAfterCloseListener()
:link:../../../../../source/gui/screens/return_values_2.java[role=include]
Объект события предоставляет информацию о том, как экран был закрыт: его метод
getCloseAction()
возвращает объект с интерфейсомCloseAction
. ИнтерфейсFrameOwner
, реализуемый контроллерами экранов, содержит несколько констант, определяющих реализацииCloseAction
, используемые фреймворком. В приложении можно использовать эти константы, либо определить свои собственные реализации.Рассмотрим следующий простой экран:
link:../../../../../source/gui/screens/return_values_3.java[role=include]
-
- при нажатии кнопки "OK", установить некоторое результирующее значение и закрыть экран со стандартным действием закрытия
WINDOW_COMMIT_AND_CLOSE_ACTION
. -
- при нажатии кнопки "Cancel", закрыть экран с действием закрытия по умолчанию.
Теперь в слушателе
AfterCloseEvent
можно проанализировать, как экран был закрыт, и, если необходимо, прочитать возвращаемое экраном значение:link:../../../../../source/gui/screens/return_values_4.java[role=include]
Другим способом возврата значений из экранов является использование собственных реализаций
CloseAction
. Перепишем пример, приведенный выше, с использованием следующего класса действия закрытия:link:../../../../../source/gui/screens/return_values_5.java[role=include]
Теперь можно использовать данное действие при закрытии экрана:
link:../../../../../source/gui/screens/return_values_6.java[role=include]
Как видно из примера кода, при возврате значений через собственный
CloseAction
, вызывающий код не обязан знать класс открываемого экрана, так как ему не нужено вызывать его методы. По тому экран можно создавать по его строковому идентификатору.Разумеется, данный подход к возврату значений через действия закрытия может использоваться и при открытии экранов с помощью
ScreenBuilders
. -