# Выборка Выборка определяет правило получения, отображение данных Рё обеспечивает взаимодействие СЃ пользователем. Выборки содержат РѕСЃРЅРѕРІРЅСѓСЋ часть интерактивной бизнес логики. Выборка определяет: - РЎРїРѕСЃРѕР± получения данных - РЎРїРѕСЃРѕР± отображения данных пользователю - Бизнес логику обработки пользовательских действий Выборка может создаваться РѕС‚ класса СЃ использованием РєРѕРґРѕ-генерации или вручную. Пользовательский интерфейс приложения является совокупностью экземпляров отображений выборок. ## Отображения Отображение – группирует бизнес логику выборки РІ зависимости РѕС‚ СЃРїРѕСЃРѕР±Р° представления данных. Стандартные отображения для класса: - `Default` – отображение РїРѕ умолчанию \ Р’ данном отображении определена функциональность общая для данных выборки. Остальные отображения выборки обычно наследуют это отображение. - `List` – отображение для СЃРїРёСЃРєР° объектов класса - `Card` – отображение для карточки объекта - Рё С‚.Рґ. ## Отношение экземпляров выборок Ркземпляры выборок, открытые РІ приложении, связаны РґСЂСѓРі СЃ РґСЂСѓРіРѕРј РІ отношении `мастер-деталь`. Рто означает, что РѕРґРЅР° выборка всегда является подчиненной Рє РґСЂСѓРіРѕР№ выборке. Подчиненная выборка имеет доступ Рє параметрам Рё данным мастер выборки. Корнем выборок экземпляра приложения – является выборка главного меню. Р’СЃРµ остальные выборки являются подчиненными Рє ней. Выборка являющаяся корнем формы имеет доступ Рє данным главного меню. Ркземпляры выборок внутри формы также выстраиваются РІ иерархии `мастер-деталь`, РІ соответствии СЃ бизнес логикой отображения.  ## Доступность параметров главных выборок РІ подчиненных выборках Получение значения параметра осуществляется СЃ помощью метода `getVar()` Рё преобразованием результата Рє нужному типу. Рерархическая структура создаваемых объектов (выборок) позволяет обеспечивать доступность Рё передачу параметров РїРѕ отношению «мастер-деталь», Р° также производить автоматическое обновление РїСЂРё изменении используемых параметров. Параметры экземпляров выборок – это, прежде всего, атрибуты (поля) РёС… датасета. Также это РјРѕРіСѓС‚ быть дополнительно созданные параметры, или специальные параметры фреймов. Параметры мастер-выборок автоматически становятся доступны РІ детальных выборках. РџСЂРё этом, главная выборка является общим, наиболее высокоуровневым мастером, поэтому РІ ней имеет смысл создавать наиболее общие параметры, используемые всем приложением. Обращение Рє параметру непосредственного мастера осуществляется прибавлением Рє имени параметра префикса `super$`. РџСЂРё этом, если необходимо обратиться Рє параметру мастер-выборки своей собственной мастер-выборки (С‚.Рµ. перепрыгнуть через РѕРґРёРЅ экземпляр выборки), необходимо использовать префикс `super$super$`. Р’ случае, если РїСЂРё любом РёР· обращений Рє параметру РѕРЅ РЅРµ будет найден, произойдет автоматический РїРѕРёСЃРє параметра РїРѕ дереву отношений "мастер-деталь" выборок вплоть РґРѕ тех РїРѕСЂ, РїРѕРєР° РјС‹ РЅРµ найдем этот параметр, или РЅРµ дойдем РґРѕ главной выборки приложений. Поэтому, РїСЂРё создании глобальных параметров РЅР° СѓСЂРѕРІРЅРµ главной выборки приложения, для РЅРёС… имеет смысл давать уникальное РёРјСЏ, Р° затем обращаться Рє РЅРёРј РёР· любого места приложения используя РѕРґРёРЅ единственный префикс `super$`. Пример получения строкового параметра РёР· мастер-выборки: ```scala getVar("super$sCaption").asNString ``` ## Передача параметров РІ выборку РџСЂРё открытии выборки, РІ нее можно передать карту СЃ дополнительными параметрами, используя метод `params()`. Пример РєРѕРґР°: ```scala Bs_GoodsAvi.defCard.newForm().params(Map(CardRep.IdItemSharp -> idvGds, CardRep.EditingType -> EditingType.edit)).open() ``` Р’ случае такой передачи параметров, РѕРЅРё становятся доступны РІ открытом отображении. ## Открытие выборок РІ различных режимах РџСЂРё открытии выборки РІ любом РёР· режимов: - newForm().open() - newForm().openModal() - newForm().openLookup() необходимо учитывать, что родителем для открывшейся выборки будет являться ***_MainMenu, Р° сама открывшаяся выборка будет главной формой (selection.isMainOnForm = true). Поэтому открывать выборки, РІ которых установлены зависимости РѕС‚ параметров (`"super$..."`) родительской выборки, без самой родительской выборки нельзя, тк никаким СЃРїРѕСЃРѕР±РѕРј РІ открывающуюся выборку РЅРµ получится передать подобные параметры. ## Разметка выборки Фреймворк использует систему декларативной разметки выборок. Рто позволяет ускорить разработку визуальных форм С‚.Рє. разработчику РЅРµ требуется заниматься низкоуровневым программированием. Разметка выборки задает правила отображения данных выборки Рё ее дочерних элементов РІ `xml` файле, СЃ расширение `.avm.xml`. Ключевые элементы разметки: - Отображения - РљРѕРјРїРѕРЅРѕРІРєР° формы - Фрейм \ Задает тип представляемых данных (СЃРїРёСЃРѕРє, дерево Рё тд.) - Атрибуты - Операции - Фильтры ### Разметка карточки. Контейнеры Существует РґРІР° режима разметки отображения: 1. Разметка РЅР° РѕСЃРЅРѕРІРµ настроек атрибутов - старый режим разметки, основанный РЅР° РїРѕСЂСЏРґРєРѕРІРѕРј номере Рё поле `isLastInLine` атрибутов. 2. Разметка РЅР° РѕСЃРЅРѕРІРµ контейнеров - новый режим, основанный РЅР° разметке СЃ помощью контейнеров, указанных внутри тэга ```<card>```. \ Разметка атрибутов может быть задана СЃ помощью следующих контейнеров: - *hBox* горизонтальный контейнер: объекты внутри располагаются РґСЂСѓРі Р·Р° РґСЂСѓРіРѕРј горизонтально. - *vBox* - вертикальный контейнер: объекты внутри располагаются РґСЂСѓРі Р·Р° РґСЂСѓРіРѕРј вертикально. - *vGroup* - РіСЂСѓРїРїР° объединения: РїРѕ сути тот же вертикальный контейнер, РЅРѕ визуально РѕР±РІРѕРґРёС‚ содержимое рамкой Рё может иметь наименование. - *vSection* - сворачиваемая секция: вертикальный контейнер, который имеет наименование Рё функцию сворачивания, которая скрывает содержимое. Можно указать, как РїРѕ умолчанию будет отображаться секция - свернутой или развернутой. Контейнеры РјРѕРіСѓС‚ быть вложены РґСЂСѓРі РІ РґСЂСѓРіР°. Пример разметки СЃ помощью контейнеров: ```scala <representation editMode="edit" name="Card" stdFilter.isAvailable="false"> <layout> <simpleComposer> <frame filter.isVisible="false"> <card> <layout> <vBox> <hBox> <vBox> <attr name="idCustomerHL"/> <attr name="dOutDate"/> </vBox> <vBox> <attr name="gidSrcDoc" visible="true"/> <attr name="nOrder"/> </vBox> </hBox> <vGroup caption="Приемка"> <attr name="idCustomerHL"/> <attr name="dExecuteDate"/> </vGroup> </vBox> <vSection caption="Примечание" collapsed="false"> <attr name="sComment" caption="Комментарий"/> </vSection> </layout> </card> </frame> </simpleComposer> </layout> <attributes/> <operations/> </representation> ```  ### Рспользование шаблонов РІ разметке. Файлы разметки поддерживают язык шаблонов [Thymeleaf](https://www.thymeleaf.org). Шаблоны позволяют вставлять РІ выборку повторно используемые фрагменты. Рљ примеру использовать общий фильтр РІ разных отображениях. Для использование шаблонов языка шаблонов необходимо подключить РІ выборку пространство имен: `xmlns:th="http://www.global-system.ru/xsd/global3-view-template-1.0"` ### Наследование разметки Для наследования разметки РґСЂСѓРіРѕР№ выборки необходимо: 1. Подключить пространство имен языка шаблонов 2. Добавить Рє тегу view указание Рѕ наследовании РґСЂСѓРіРѕР№ разметки `th:extends="Some_Other.avm.xml"` Полный пример xml СЃ наследованием: ```xml <view xmlns="http://www.global-system.ru/xsd/global3-view-1.0" xmlns:th="http://www.global-system.ru/xsd/global3-view-template-1.0" name="RplTst_AllDbTypes" th:extends="RplTst_AllDbTypes.dvm.xml"> <representation name="Default"/> </view> ``` Алгоритм наследования выборки: 1. РџСЂРё отсутствие скопировать отображения предка РІ наследника \ Копирование РїСЂРѕРёСЃС…РѕРґРёС‚ РІ случаи если РІ наследники нет данного отображения 2. Произвести наследование отображений \ Наследование производится РІ случаи если Рё РІ предке Рё РІ потомке есть отображение СЃ тем же именем. 3. Выполнить оставшиеся команды языка разметки Алгоритм наследования отображений: 1. РџСЂРё отсутствие скопировать - levelGroups - bandGroups - layout - filter 2. Добавить отсутствующие атрибуты 3. Добавить отсутствующие операции ## Операции Выборка взаимодействует СЃ программным окружением системы СЃ помощью операций. Операция – это некая обработка того или РёРЅРѕРіРѕ события, вызванного пользователем или каким-то процессом. Операции бывают служебными, выполняя логику обработки событий, или пользовательскими, срабатывающими РІ результате СЏРІРЅРѕРіРѕ действия пользователя. ### Классификация операций - *Базовые операции* \ Операции, предназначенные для работы СЃ набором данных. РћРЅРё отвечают Р·Р° добавление, удаление, обновление записей, получения данных, навигацию РїРѕ датасету Рё С‚.Рї. Рти операции, как правило, уже определены РЅР° СѓСЂРѕРІРЅРµ базовых выборок-предков. Некоторые РёР· этих операций срабатывают автоматически РЅР° выполнение определенных пользовательских действий (`BeforeEdit` РїСЂРё начале редактирования, `AfterEdit` РїСЂРё завершении, `CheckWorkAbility` РїСЂРё перемещении СЃ записи РЅР° запись) - *Служебные операции* \ Операции, выполняющие строго определенные вспомогательные действия - *Системные операции* \ Операции, создающиеся автоматически - *Сеттеры* \ Операции предназначены для изменения значений атрибутов (полей) выборки. РџСЂРё РІРІРѕРґРµ значения РІ какое-то поле формы вызывается связанная СЃ данным полем операция (сеттер), которая РїРѕ умолчанию вызывает серверные методы изменения значений атрибутов класса. Сеттеры для атрибутов класса создаются автоматически. - *Операции фильтров* \ Операции, необходимые для работы СЃ фильтрами. - *Пользовательские операции* Операции, создаваемые разработчиком самостоятельно Рё позволяющие осуществлять любой набор необходимых операций, РЅРµ только осуществляемых над данными, РЅРѕ Рё являющихся целиком клиентскими (например, вызов РґСЂСѓРіРѕР№ формы, сообщения Рё С‚.Рї.). ### Базовые операции выборки РЎ точки зрения автоматического срабатывания операций РЅР° различные системные действия, ключевым параметром операций является РёС… системное РёРјСЏ. Базовые Рё служебные операции выборки имеют предопределенные системные имена. #### onRefresh Операция, загружающая данные РІ датасет. РџСЂРё повторном вызове РїСЂРѕРёР·РІРѕРґРёС‚ обновление всего набора данных (`refresh`). #### onRefreshItem Операция обновления РѕРґРЅРѕР№ (текущей) записи. #### onRefreshExt Операция СЃ дополнительным запросом Рє базе для получения полей-заголовков ссылочных объектов. Вызывается только для объектных запросов РІ onRefresh/onRefreshItem. \ Для использования РІ запросе атрибутов класса необходимо передать РёС… РІ блоке `with`. РџСЂРё этом обязательно для РќР• `Long` атрибутов нужно СЏРІРЅРѕ указывать тип РІ аннотации `/*@...*/`: \ - Для `Varchar` атрибутов - "String", "NString" или "varchar", например - `/*@NString*/` - Для `Number` атрибутов - "Number", например - `/*@Number*/` Р’ противном случае атрибуты попытаются преобразоваться Рє `bigint` типу. #### beforeEdit Операция, выполняемая перед началом редактирования записи для выполнения подготовительных действий перед началом редактирования. Автоматически выполняется РІ момент начала внесения изменений РІ объект. #### afterEdit Операция финальной проверки РІРІРѕРґР° записи. Срабатывает автоматически РїСЂРё попытке перейти СЃ отредактированной записи РЅР° РґСЂСѓРіСѓСЋ запись выборки или РїСЂРё закрытии выборки. #### insert Операция вставки РЅРѕРІРѕР№ записи РІ выборку. #### delete Операция удаления записи. #### checkWorkAbility Операция, предназначенная для осуществления проверок изменения состояния операций выборок, доступности редактирования ее атрибутов. Вызывается автоматически РїСЂРё переходе СЃ записи РЅР° запись, РїСЂРё открытии выборки, Р° также после выполнения операции, для которой выставлен флаг "выполнять операцию применимости после выполнения операции". #### onLoadMeta Операция, срабатывающая РїСЂРё загрузке метаданных. Рў.Рє. метаданные загружаются только РѕРґРёРЅ раз, РїСЂРё первом открытии экземпляра выборки РЅР° фрейме, то Рё данная операция срабатывает только РѕРґРёРЅ раз. #### onUnloadMeta Операция, срабатывающая РїСЂРё выгрузке метаданных. #### beforeOpen Операция, срабатывающая перед открытием выборки. Данная операция рекомендуется для создания дополнительных параметров, используемых РІ выборке. #### afterOpen Операция, срабатывающая сразу после открытия выборки. Необходимо использовать для переопределения наименований столбцов выборки Рё С‚.Рґ. #### onShow Операция, срабатывающая сразу после того, как отрисован интерфейс формы Рё были созданы элементы формы. #### onControllerCreated Операция, срабатывающая сразу после того, был создан фрейм отображения выборки. Рта операция аналогична OnShow, РЅРѕ срабатывает РІ том числе Рё РїСЂРё открытии интерфейсных элементов формы, которые были скрыты РїСЂРё открытии формы (например, закладки, которые РЅРµ были первыми РІ перечне закладок). ### Служебные операции выборки #### saveForm Операция сохраняет данные формы. #### cancelForm Операция отменяет изменения РЅР° форме. #### closeFormOk Операция закрытия формы СЃ подтверждением выбора #### closeFormCancel Операция закрытия формы РїРѕ РєРЅРѕРїРєРµ "Выход" или РїРѕ РєРЅРѕРїРєРµ закрытия РѕРєРЅР° "крестик" #### beforeCloseForm Операция срабатывает перед закрытием формы. #### afterCloseForm Операция срабатывает после закрытия формы. #### onCloseFormQuery Операция вызывается РІ начале процесса закрытия формы Рё позволяет отменить закрытие. ### Предопределенные операции выборок #### applyUniFilter Операция применяет настроенные условия фильтрации, выполняется перезапрос данных СЃ наложенными условиями фильтрации. #### resetUniFilter Операция отменяет РІСЃРµ наложенные РЅР° выборку фильтры #### clearUniFilter Операция отчищает РІСЃРµ условия фильтрации. #### showAuditObject Операция вызывает РѕРєРЅРѕ аудита выполняемых пользователями действий РІ БД, СЃ наложенным фильтром РїРѕ текущему объекту. #### showAboutObject Операция открывает РѕРєРЅРѕ системной информации РѕР± объекте. #### copyObject Операция копирования объекта #### cardEdit Операция открытия объекта РІ карточке, предварительно запросив, какую использовать выборку Рё отображение. #### allowEdit Разрешение/запрещение редактирования объектов РІ СЃРїРёСЃРєРµ. РџРѕ умолчанию операция доступна для редактируемых СЃРїРёСЃРєРѕРІ. #### showTab Операция открытия/закрытия детальной части ### Сеттеры изменения атрибутов Операции установки значений атрибутов (так называемые сеттеры) используются для того, чтобы установить определенное значение РІ поле записи объекта, соответствующее его типу. РРјСЏ сеттера состоит РёР· префикса `set` Рё имени атрибута `attributeName`: `setattributeName`. ### Специальные операции контролов #### onFocusedFieldChanged Рто специальная операция, срабатывающая после перехода фокуса РІРІРѕРґР° РІ СЃРїРёСЃРєРµ или дереве СЃ РѕРґРЅРѕРіРѕ столбца РЅР° РґСЂСѓРіРѕР№, Р° также РїСЂРё переходе СЃ контрола РЅР° контрол РІ карточке или панели фильтров. #### onFocusedCellChanged Рто специальная операция, срабатывающая после перехода фокуса РІРІРѕРґР° РІ СЃРїРёСЃРєРµ СЃ РѕРґРЅРѕР№ ячейки РЅР° РґСЂСѓРіСѓСЋ. #### onFrameActivated Специальная операция, срабатывающая РїСЂРё переходе фокуса РІРІРѕРґР° РІ РіСЂРёРґ, дерево, карточку. ### РЎРїРѕСЃРѕР±С‹ визуализации операций Существует 3 основных СЃРїРѕСЃРѕР±Р° визуального отображения операций: - РќР° тулбаре фрейма - Р’ выпадающем (контекстном) СЃРїРёСЃРєРµ (popup меню) - Р’ качестве пункта главного меню (доступно только для выборок приложений главного меню) Для настройки отображения операции каждым РёР· СЃРїРѕСЃРѕР±РѕРІ существует собственная настройка РїСЂРё помощи соответствующих свойств операции. ## Диалоги Диалоги позволяют задавать РІРѕРїСЂРѕСЃС‹ пользователю Рё получать РѕС‚ него ответы РЅР° эти РІРѕРїСЂРѕСЃС‹. Для доступа Рє методам диалогов используется специальный объект `ru.bitec.app.gtk.gl.Dialogs`, который доступен РІ `Avi` через переменную `dialogs`. РљСЂРѕРјРµ стандартных диалогов, есть возможность открыть форму РІ режиме выбора (`openLookup`) Рё после обработать выбранное пользователем значение, что так же РёР· себя представляет специализированный РІРёРґ диалогов. ### Стандартные диалоги #### showMessage Выводит РЅР° экран текст РІ модальном РѕРєРЅРµ. Пример использования: ```scala dialogs.showMessage("Текст, который СѓРІРёРґРёС‚ пользователь") ``` #### showMsgDialog Открывает диалог указанного типа СЃ сообщением Рё указанным перечнем РєРЅРѕРїРѕРє. Возможные типы диалогов СЃРј. РІ `ru.bitec.app.gtk.gl.msgdlg.MsgDlg` Возможные типы РєРЅРѕРїРѕРє СЃРј. РІ `ru.bitec.app.gtk.gl.msgdlgbutton.MsgDlgButton`g Пример использования: ```scala val dlgRes = dialogs.showMsgDialog( //тип диалога "Подтверждение" MsgDlg.confirmation, //текст диалога "Включить автонумерацию?", //СЃРїРёСЃРѕРє РєРЅРѕРїРѕРє: Да, Нет List(MsgDlgButton.yes,MsgDlgButton.no) ) if (dlgRes == MsgDlgButton.yes) { //обработка нажатия РЅР° РєРЅРѕРїРєСѓ "Да" } else if (dlgRes == MsgDlgButton.no) { //обработка нажатия РЅР° РєРЅРѕРїРєСѓ "Нет" } ``` #### showButtonsDialog Открывает диалог СЃ произвольными кнопками. Позволяет формировать диалоги, РєРЅРѕРїРєРё которых Р±СѓРґСѓС‚ РЅРµ РёР· перечня стандартных РєРЅРѕРїРѕРє. Пример использования: ```scala dialogs.showButtonsDialog( caption = "", text = "Удалить форму или убрать ссылку РЅР° РІРёРґ отчетности?", colCount = 2, buttons = List(List("Удалить"), List("Убрать ссылку")), imageCollectionName = "ToolBarPrimaryHot", focusButtonNumber = 0L ) match { case 0L => //обработка нажатия РєРЅРѕРїРєРё "Удалить" case 1L => //обработка нажатия РєРЅРѕРїРєРё "Убрать ссылку" } ``` #### showPromptDialog Открывает диалог СЃ запросом РІРІРѕРґР° строки. Пример использования: ```scala val svDialogRes = dialogs.showPromptDialog("Заголовок РѕРєРЅР°", "Текст диалога", "Значение РїРѕ умолчанию").ns if (svDialogRes.isNotNullOrEmpty) { //обработка введенного значения } ``` #### showConfirmDialog Открывает диалог СЃ типом "Подтверждение" Рё кнопками "Да" Рё "Нет" Пример использования: ```scala val dialogRes = dialogs.showConfirmDialog("Текст диалога") if (dialogRes){ //обработка случая, РєРѕРіРґР° пользователь нажал "Да" } ``` #### showInfoForm Отображает информационное сообщение СЃ переданным текстом, без возможности его закрытия пользователем. Скрывается РїСЂРё вызове метода `hideInfoForm`. Применяется, РєРѕРіРґР° РІ бизнес-логике выполняется продолжительная задача, Рё требуется проинформировать пользователя РѕР± ее выполнении. Пример использования: ```scala dialogs.showInfoForm("Внимание, идет загрузка Госреестра типов РЎР") try { //продолжительное действие thisApi().download() } finally { dialogs.hideInfoForm() } ``` #### hideInfoForm Скрывает информационное сообщение, СЃРј. описание метода `showInfoForm` #### withInfoForm Метод включает РІ себя открытие информационного РѕРєРЅР°, Рё его закрытие после завершение выполнения переданной функции. Пример РёР· описания метода `showInfoForm`, можно переписать используя этот метод: ```scala dialogs.withInfoForm("Внимание, идет загрузка Госреестра типов РЎР") { //продолжительное действие thisApi().download() } ``` #### showEditPaintStyleDialog Вызывает диалог настройки стилей раскраски текстовых полей. ### Форма РІ режиме выбора значения РћРґРЅРѕР№ РёР· типичных задач является предложить выбрать пользователю какой-либо объект Рё затем сделать обработку его выбора. Например, чаще всего ссылочные поля открывают для выбора СЃРїРёСЃРѕРє объектов ссылочного класса, Р° после выбора пользователем значения устанавливают его РІ текущей форме. Для реализации такого типа диалогов используется синтаксис открытия формы РІ режиме `openLookup`. Пример открытия формы Рё обработки выбора пользователя: ```scala //создаем РЅРѕРІСѓСЋ форму val data = Btk_ClassAvi.listForChoose().newForm() //указываем СЃРїРёСЃРѕРє полей, которые требуется получить РёР· формы .results("id" :: "sCaption" :: Nil) //открываем форму РІ режиме выбора .openLookup() //проверяем, что пользователь подтвердил выбор if (data.getLookupResult eq LookupResult.ok) { //получаем значение первого поля РёР· СЃРїРёСЃРєР° results val id = data.getData(1, 0) //получаем значение второго поля РёР· СЃРїРёСЃРєР° results val sCaption = data.getData(1, 1) } ``` #### Выбор нескольких строк (мультиселект) Для того, чтобы РІ форме РІ режиме выбора пользователь РјРѕРі выбрать несколько строк используется опция `useMultiSelect`. Пример открытия формы РІ режиме мультиселекта Рё обработка выбранных значений: ```scala //создаем РЅРѕРІСѓСЋ форму val data = Btk_ClassAvi.listForChoose().newForm() //указываем СЃРїРёСЃРѕРє полей, которые требуется получить РёР· формы .results("id" :: "sCaption" :: Nil) //указываем возможность выбора нескольких строк .useMultiSelect //открываем форму РІ режиме выбора .openLookup() //проверяем, что пользователь подтвердил выбор if (data.getLookupResult eq LookupResult.ok) { //цикл РїРѕ выбранным строкам for (i <- 1 to data.size) { //получаем значение первого поля РёР· СЃРїРёСЃРєР° results для строки i val id = data.getData(i, 0) //получаем значение второго поля РёР· СЃРїРёСЃРєР° results для строки i val sCaption = data.getData(i, 1) } } ``` ## Фрейм Фреймы — это средство представления информации РІ выборке. Существующие фреймы РїРѕ СЃРїРѕСЃРѕР±Сѓ представления информации можно разделить РЅР° несколько РІРёРґРѕРІ: - для отображения информации РІ РІРёРґРµ карточки объекта - для отображения СЃРїРёСЃРєР° объектов РІ табличной форме - для отображения СЃРїРёСЃРєР° объектов РІ РІРёРґРµ древовидной структуры - для отображения инфографики - специализированные (для отображения графической информации, доступа Рє файлам Рё С‚.Рґ.) ### Основные типы фреймов #### grid Фрейм для вывода СЃРїРёСЃРєР° объектов класса РІ табличной форме  #### tree Фрейм для вывода СЃРїРёСЃРєР° объектов класса РІ древовидной форме  #### card Фрейм для вывода всех атрибутов конкретного объекта (Карточка)  #### tab Фрейм СЃ закладками. Выборка фрейма является источником СЃРїРёСЃРєР° закладок. Так же, закладки РјРѕРіСѓС‚ быть указаны статически, РІ xml-разметке. #### memo Фрейм для РІРІРѕРґР° большого количества текстовой информации (Memo)  #### html Фрейм, отображающий HTML  #### image Рзображение  #### gantt Фрейм, для построения диаграмм Ганта.  #### olap Фрейм для построения сводных (OLAP) таблиц #### bpmn Фрейм редактора диаграмм бизнес-процессов. Поддерживает диаграммы BPMN версии 2.0  #### gridPanel Позволяет размещать детальные фреймы РІ РІРёРґРµ таблицы, для указания ширины Рё высоты ячеек которой можно использовать как абсолютные, так Рё относительные величины.  ### Основные типы редакторов #### button Редактор - РљРЅРѕРїРєР°. РџСЂРё нажатии выполнится сеттер соответствующего атрибута.  #### buttonsEdit Редактор РІ строке СЃ произвольными кнопками. Если РЅРё РѕРґРЅРѕР№ РєРЅРѕРїРєРё для отображения РЅРµ задано, РїРѕ умолчанию будет отображена РєРЅРѕРїРєР° lookup.  #### calendar Редактор - Календарь.  #### check Редактор - Чекбокс (Галка).  #### colorPick Редактор - Выбор цвета.  #### combo Редактор - Фиксированный выпадающий СЃРїРёСЃРѕРє. #### currency Денежный редактор.  #### datePick Редактор даты.  #### dateTimePick Редактор даты Рё времени.  #### edit Однострочный редактор текста.  #### editButton Редактор: Редактор РІ строке СЃ РєРЅРѕРїРєРѕР№.  #### hotKey Редактор РІРІРѕРґР° комбинации горячих клавиш. #### hyperLink Редактор адреса СЌР».почты Рё гипер-ссылок.  #### icon Редактор - изображение. Рспользуется для СЃРїРёСЃРєР° Рё дерева. Отображает изображение РёР· коллекции изображений.  #### lookup Редактор - Выпадающий СЃРїРёСЃРѕРє РїРѕ запросу. Рсточником элементов РјРѕРіСѓС‚ являться: выборка или SQL-запрос, указанные РІ свойствах.  #### memo Многострочный редактор. Предназначен для редактирования многострочных текстовых значений без разметки.  #### tagLookup Редактор - Выпадающий СЃРїРёСЃРѕРє РїРѕ запросу СЃ возможностью множественного выбора.  #### timePick Редактор времени.  #### editPassword Редактор РІРІРѕРґР° пароля.  #### imageCollection Редактор - выпадающий СЃРїРёСЃРѕРє изображений.  ## Мультиселект Мультиселект - возможность выбрать несколько строк РІ списках или деревьях. Для включения мультиселекта РІ отображении укажите РІ теге `grid` или `tree` свойство `isMultiSelectEnabled="true"`. Пример разметки: ```xml <representation name="List"> <layout> <simpleComposer> <frame> <grid isMultiSelectEnabled="true"/> </frame> </simpleComposer> </layout> </representation> ``` Пример обработки выделенных строк пользователем Рё получения значений атрибутов этих строк: ```scala //цикл РїРѕ выделенным строкам for (i <- 0 until selection.selectedRecordsCount()) { //получение значения поля СЃ типом NLong val id = NLong.fromAny(selection.selectedValueByName("id", i)) //получение значения поля СЃ типом NNumber val nOrder = NNumber.fromAny(selection.selectedValueByName("nOrder", i)) //получение значения поля СЃ типом NGid val gid = NGid(selection.selectedValueByName("gid", i).asInstanceOf[String]) //получение значения поля СЃ типом NString val sCaption = selection.selectedValueByName("sCaption", i).asInstanceOf[String].ns //получение значения поля СЃ типом NDate val dDate = NDate(selection.selectedValueByName("dDate", i).asInstanceOf[JDate]) } ``` ~~~{note} Для формы РІ режиме выбора мультиселект регулируется опцией `useMultiSelect` РїСЂРё создании формы. Подробнее РІ главе `Диалоги` ~~~ ## Настройка стилей Стиль - набор свойств, включающий РІ себя: - `Color` - Цвет заднего фона РІ формате `$00BBGGRR` или Global константой цвета. - `FontColor` - Цвет шрифта РІ формате `$00BBGGRR` или Global константой цвета. - `FontSize` - Размер шрифта натуральным числом. - `FontItalic` - РљСѓСЂСЃРёРІ. Значение `0` - нет РєСѓСЂСЃРёРІР°, `1` - есть РєСѓСЂСЃРёРІ. - `FontBold` - Жирность. Значение `0` - РЅРµ жирный шрифт, `1` - жирный шрифт. - `FontUnderLine` - Подчеркивание. Значение `0` - нет подчёркивания шрифта, `1` - есть подчёркивание шрифта. - `FontStrikeOut` - Перечеркивание. Значение `0` - нет перечеркивания шрифта, `1` - есть перечеркивание шрифта. Стиль задаётся строкой формата: ```scala "param1=value1;param2=value2;param3=value3;...;paramn=valuen" ``` Пресеты стилей хранятся РІ классе `Btk_Registry`, РёС… можно использовать для типовых задач. Стили можно применять РІ отображении Рє строкам Рё столбцам. ### Применение стиля Рє строке Чтобы применить стиль Рє строке, нужно РІ теге `representation` присвоить свойству `rowStyleAttr` РёРјСЏ атрибута, РІ котором будет храниться либо готовая строка СЃРѕ стилем, либо системное РёРјСЏ пресета. ```xml <representation name="List" editMode="notEdit" rowStyleAttr="sStyle1"> <attributes> <attr name="sCode" caption="РљРѕРґ" editorType="edit" order="10" isRequired="true"/> <attr name="sCaption" caption="Наименование" editorType="edit" order="20" isRequired="true"/> <attr name="sStyle1" caption="Первый стиль" editorType="edit" order="40"/> </attributes> </representation> ```  ### Применение стиля Рє столбцу Чтобы применить стиль Рє столбцу, нужно РІ теге `attr` создать тег `style` Рё РІ нём использовать либо свойство `name`, либо `attr`. Р’ свойстве `name` указывается непосредственно строка стиля или системное РёРјСЏ пресета, РІ `attr` указывается атрибут, РіРґРµ хранится либо строка, либо системное РёРјСЏ. ```xml <representation name="List" editMode="notEdit"> <attributes> <attr name="sCode" caption="РљРѕРґ" editorType="edit" order="10" isRequired="true"> <style name="Color=$00880000"/> </attr> <attr name="sCaption" caption="Наименование" editorType="edit" order="20" isRequired="true"> <style name="BDG_URTotalRow"/> </attr> <attr name="sStyle1" caption="Первый стиль" editorType="edit" order="40"> <style attr="sStyle1"/> </attr> </attributes> </representation> ```  Также стиль можно менять РІ avi используя `selection` ```scala selection.attrs("РРјСЏ атрибута, РЅР° который РјС‹ хотим применить стиль").styleAttributeName = "РРјСЏ атрибута СЃРѕ строкой стиля или СЃ системным именем пресета" ``` ## Создание строки стиля. StyleBuilder StyleBuilder - класс, позволяющий работать СЃРѕ стилем РЅРµ как СЃРѕ строкой, Р° как СЃ объектом, РІ котором хранятся параметры. РџРѕРјРёРјРѕ этого РІ StyleBuilder хранятся цветовые Рё шрифтовые константы для удобства использования. Внутри класса хранится изменяемый словарь, который хранит пары `название параметра GS -> (значение параметра, название параметра CSS)`. Для его корректной работы есть вспомогательный неизменяемый словарь, хранящий пары `название параметра GS -> название параметра CSS`. Р’СЃРµ манипуляции СЃРѕ словарём РїСЂРѕРёСЃС…РѕРґСЏС‚ через сеттеры Рё геттеры. Для создания результирующей строки тоже есть отдельный метод. Рзначально класс создан для стилей, которые используются РІ Global, РЅРѕ класс также поддерживает создание результирующей строки Рё для CSS. ### Создание экземпляра StyleBuilder Для использования StyleBuilder нужно сначала создать его экземпляр. Можно создать как Рё пустой стиль ```scala val builder = StyleBuilder() builder.build() //Результирующая строка пустая ``` так Рё взять Р·Р° РѕСЃРЅРѕРІСѓ уже существующую строку стиля ```scala val stringStyle = "color=$00FF4400;font=arial;fontsize=15".ns val builder = StyleBuilder(stringStyle) builder.build() //Р’ результирующей строке Р±СѓРґСѓС‚ РІСЃРµ те же параметры c теми же значениями, //что Рё РІ stringStyle, РЅРѕ возможно параметры Р±СѓРґСѓС‚ расположены РІ РґСЂСѓРіРѕРј РїРѕСЂСЏРґРєРµ. ``` ### Работа СЃ цветовыми параметрами Для работы СЃ цветовыми параметрами внутри StyleBuilder создан класс Color. Методы работы СЃ цветовыми параметрами принимают РЅР° РІС…РѕРґ Рё возвращают экземпляры этого класса. РќР° РІС…РѕРґ РІ сеттер можно подавать обычную строку типа String, РѕРЅР° будет неявно преобразована РІ экземпляр Color. РџСЂРё создании РѕС‚ строки Color пытается преобразовать цвет РІ HEX, если цвет невозможно преобразовать - бросается исключение. Color умеет преобразовывать строки типа: * `$00BBGGRR` * `$BBGGRR` * `#RRGGBB` * Наименование GS константы РР· Color можно получить строку обратно РІ формате HEX или GS РєРѕРґР°: ```scala val color = Color.Red //Р’ Color есть константы Gs цветов //РЛРval color = Color("$000000FF") //РЛРval color = Color("$0000FF") //РЛРval color = Color("#FF0000") //РЛРval color = Color("clRed") //------------------------------- color.getGsHex // Вернётся $000000FF color.getHex // Вернётся #FF0000 ``` Если РІ Color подать пустую строку - это считается как отсутствие цвета. ### Примеры ```scala val style = StyleBuilder() .setBackgroundColor(Color.Blue) .setFontColor("#FFAAFF") .setFont(Font.Impact) .setFontUnderLine(1.nn) .build() // style = "color=$00FF0000;fontcolor=$00FFAAFF;fontunderline=1;fontname=Impact" val style2 = StyleBuilder(style) .setBackgroundColor(Color("")) // Убрать параметр цвета заднего фона .setFontColor("$00FFFFFF") .setFont("") // Убрать параметр шрифта .setFontUnderLine(NNumber()) // Убрать параметр нижнего подчёркивания .setFontBold(1.nn) .buildCSS // style2 ="color: #FFFFFF; // font-weight: bold;" ``` ## Жизненный цикл формы  ## РРєРѕРЅРєРё Фреймворк поддерживает три варианта подключения РёРєРѕРЅРѕРє: 1. РР· ресурсов сервера (РѕСЃРЅРѕРІРЅРѕР№ режим) \ Коллекции изображений берутся РёР· каталога СЃ ресурсами `[G3_HOME]/resources/imagecollection`. Каждый подкаталог является коллекцией, вложенные файлы - элементы коллекции, номера которых соответствуют именам файлов. 2. РР· базы данных \ Коллекции изображений загружаются РёР· таблицы `btk_component`, поле `clobdataxml` 3. Подключение РёРєРѕРЅРєРё РїРѕ url Для РёРєРѕРЅРєРё указывается явный url ### Рспользование РёРєРѕРЅРѕРє РёР· java-ресурсов модуля Файлы изображений размещаются РІ ресурсных каталогах соответствующего модуля. РќР° скриншоте приведён пример структуры каталогов СЃ ресурсами модуля BTK. Коллекции изображений размещены РІ каталоге ресурсов `../ru/bitec/app/btk/images`. Каждой коллекции соответствует одноимённый каталог. Рассмотрим структуру каталога `ru/bitec/app/btk/images/toolbar`. - Р’ РєРѕСЂРЅРµ каталога размещаются файлы изображений СЃ минимальным разрешением 16С…16 точек. - Р’ подкаталоге `ru/bitec/app/btk/images/toolbar/24x24` размещаются файлы изображений СЃ разрешением 24С…24 точек. Р’ случае необходимости РјРѕРіСѓС‚ быть добавлены каталоги изображений СЃ большим разрешением. - Подкаталог `ru/bitec/app/btk/images/toolbar/disabled` содержит обесцвеченные РєРѕРїРёРё изображений коллекции toolbar, необходимые для отображения неактивных операций РЅР° панелях управления. Пример указания изображения для операции СЃ использованием аннотации: ```scala @Oper( caption = "Р РѕРґ", headOperation = "references", imageUri ="ru/bitec/app/gs3/images/toolbar/61.png") def open_Bs_Kind_RoList(): Unit = { Bs_KindAvi.roList().newForm().open() } ``` РџСЂРё одновременном указании свойств `imageIndex` Рё `indexUri`, второе имеет приоритет. ## Частично-загружаемые деревья ### Введение Частично-прогружаемое дерево – это такой РІРёРґ отображения, РіРґРµ СЃРїРёСЃРѕРє РІ форме дерева подгружается РёР· базы только для тех записей, которые раскрыты РІ дереве. Частично прогружаемые деревья используются для отображений, РІ которых заведомо известно, что будет РѕРіСЂРѕРјРЅРѕРµ количество записей, например `Mct_Structure`. ### Настройка avm файла Для отключения полной загрузки дерева РІ avm файле РІ настройках отображения необходимо указать свойство ``` fetchAllTree="false" ``` РџРѕРјРёРјРѕ этого, РІ настройках фрейма необходимо указать наименование атрибута, отвечающего Р·Р° отображение наличия Сѓ записи потомков ```xml <tree idAttr="gid" idParentAttr="gidParent" hasChildrenAttr="bHasChild" /> ``` ### Настройка refresh Для отображения необходимых записей нужно получить СЃРїРёСЃРѕРє `idAttr` Рё `idParentAttr`, РїРѕ которым Р±СѓРґСѓС‚ загружаться данные РёР· базы. Для этого нужно воспользоваться значениями параметров выборки `OPENNODEIDARRAY` Рё `OPENNODEID` - `OPENNODEIDARRAY` \ Параметр выборки, хранящий РІ себе СЃРїРёСЃРѕРє открытых РЅРѕРґ через запятую РІ формате `ftString` - `OPENNODEID` \ Параметр выборки, передающий `idAttr` открываемой РЅРѕРґС‹ РІ формате `ftString` `OPENNODEIDARRAY` Рё `OPENNODEID` – системные параметры. Пользовательская установка значений этих параметров запрещена ### Пример Пример запроса для `Mct_StructureAvi#StructureTree`, находящегося РІ пакете `Mct_StructurePkg.getOnRefreshBs` ```sql --Рї.1.- открытые узлы with nodes as ( SELECT distinct tVal.tVal as gid FROM regexp_split_to_table( concat_ws( ', ' ,:OpenNodeIdArray# ,:OpenNodeIdArray ) ,', ' ) tVal where :OpenNodeId is null -- узлы нужны только РїСЂРё рефреше union select :gidParent as gid where :gidCurrentGid# is not null ), -- фильтрация объектов для вывода РІ дерево gidFlt as ( select h.gid ,h.gidParent from ( -- Рї.2. блок рефреша узлов "RefreshNodes" select t.gid ,case when ll.id is null then null else l.gidParent end as gidParent from mct_structure t join mct_structurelink l on l.gidstructure=t.gid left join mct_structurelink ll on ( l.gidparent=ll.gidstructure and l.idviewtype=ll.idviewtype ) where t.idPrjVer = :flt_idPrjVer and l.idviewtype=:flt_idViewType and l.gidparent in (select n.gid from nodes n) -- Блок OnRefresh union all -- Рї.3. 1. Раскрываем заказ – корневые записи select t.gid ,null as gidParent from mct_structure t join mct_structurelink l on l.gidstructure=t.gid l.idviewtype=ll.idviewtype ) --left join mct_structure tt on (l.gidparent=tt.gid) where t.idPrjVer = :flt_idPrjVer and l.idviewtype=:flt_idViewType and not exists ( select 1 from mct_structurelink ll where ll.gidstructure=l.gidparent and ll.idviewtype=:flt_idViewType) and :OpenNodeId is null -- union all --Рї.4. - 2. Раскрываем потомков – РїРѕ нажатию РЅРѕРґС‹ select l.gidstructure as gid ,l.gidparent from mct_structurelink l where l.idviewtype = :flt_idViewType and l.gidparent = :OpenNodeId ) h --Рї.5. SELECT t.id ,t.idClass ,t.gid ,tt.gidParent ,(select COALESCE(max(1),0) from mct_structurelink l where l.gidparent=t.gid) as bHasChild ,t.gidDoc ,t.gidDocVer ,t.gidSourceObj ,t.idPrjVer ,t1.sCode as idPrjVerHL ,t.idEskd ,t2.sCaption as idEskdHL ,t.idPosType ,t3.sCaption as idPosTypeHL ,t.sCode ,t.sCaption ,t.sSysName FROM Mct_Structure t join gidFlt tt on t.gid=tt.gid LEFT JOIN Bs_PrjVer t1 on t.idPrjVer = t1.id LEFT JOIN Mct_Eskd t2 on t.idEskd = t2.id LEFT JOIN Mct_PosType t3 on t.idPosType = t3.id LEFT JOIN Bs_Goods t4 on t.idGds = t4.id LEFT JOIN Msr_MeasureItem t5 on t.idMsr = t5.id LEFT JOIN Mct_OrderSheet t6 on t.idOrderSheet = t6.id ``` - *Рї.1* \ Получение таблицы значений открытых РЅРѕРґ СЃ учетом открытия РЅРѕРґС‹ для РЅРѕРІРѕР№ созданной записи уровнем ниже - *Рї.2* \ Получение записей, которые РІС…РѕРґСЏС‚ РІ открытые РЅРѕРґС‹ - *Рї.3* \ Получение корневых записей дерева - *Рї.4* \ Получение записей, которые РІС…РѕРґСЏС‚ РІ открытую РЅРѕРґСѓ – блок, срабатывающий РїСЂРё первом раскрытии РЅРѕРґС‹ - *Рї.5* \ РћСЃРЅРѕРІРЅРѕР№ запрос для получения необходимых колонок. Так же важно обратить внимание, что РІ РѕСЃРЅРѕРІРЅРѕРј запросе присутствуют изменения: - Добавлен атрибут bHasChild \ Признак наличие дочерних элементов. \ Текст запроса атрибута: ```sql (select COALESCE(max(1),0) from mct_structurelink l where l.gidparent=t.gid) as bHasChild ``` - Добавлено ограничение получения записей РїРѕ отфильтрованному СЃРїРёСЃРєСѓ ```sql join gidFlt tt on t.gid = tt.gid ``` ### Загрузка дочерних записей РЅР° открытие Если необходимо открыть выборку СЃ уже прогруженными дочерними записями, можно РїСЂРё открытии передать РІ качестве параметров СЃРїРёСЃРѕРє РЅРѕРґ для РїСЂРѕРіСЂСѓР·РєРё. Р РІ качестве параметра, используемого РІ `refresh`-Рµ использовать его. Однако, РІ таком случае РІСЃРµ РЅРѕРґС‹ Р±СѓРґСѓС‚ закрыты Рё РёС… нужно будет открывать вручную. ~~~{note} Рзменение параметров, участвующих РІ запросе, спровоцирует операцию `refresh`! ~~~ Для установки параметров без вызова `refresh` необходимо воспользоваться конструкцией ```scala try { selection.ignoreParamChange = true setVar("gidParent", curGidParent) setVar("gidCurrentGid#", thisRop().gid) } finally { selection.ignoreParamChange = false } ``` ## Пример разметки выборки ```xml <?xml version="1.0"?> <view xmlns="http://www.global-system.ru/xsd/global3-view-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.global-system.ru/xsd/global3-view-1.0" name="Bs_GdsCostDeviationType"> <representation name="Default" doubleClickOperation.createFormMode="CardEdit" doubleClickOperation.lookupMode="CloseFormOK" caption="Р’РёРґС‹ отклонений РІ стоимости РўРњР¦"> <filter name="Bs_GdsCostDeviationTypeFilter"> <macros name="DefFltReferenceMacro"> <condition logicalOperator="and" id="shownotused" isExpression="true" expression="(:filter$flt_bShowNotUsed = 1 or (coalesce(t.bnotactive,0) = 0 and (t.dexpirydate is null or t.dexpirydate > current_date) ) )"> <filterAttr name="flt_bShowNotUsed" attribute-type="Long" caption="Отображать неиспользуемые" isLastInLine="false" order="10" defaultValue="0" editorType="check"/> </condition> </macros> </filter> <layout> <simpleComposer> <frame filter.isVisible="true" toolBar.isVisible="true"> <grid/> </frame> </simpleComposer> </layout> <attributes> <attr name="id" caption="Рдентификатор" isVisible="false" editorType="edit" order="-1"/> <attr name="idClass" caption="idClass" isVisible="false" editorType="edit" order="-2"/> <attr name="gid" isVisible="false" editorType="edit"/> <attr name="sCode" caption="РљРѕРґ" editorType="edit" order="10" isRequired="true"/> <attr name="sCaption" caption="Наименование" editorType="edit" order="20" isRequired="true"/> <attr name="sDescription" caption="Описание" editorType="memo" order="30"/> <attr name="bNotActive" caption="РќРµ используется" editorType="check"/> <attr name="dExpiryDate" caption="Дата окончания использования" editorType="datePick"/> </attributes> <operations> </operations> </representation> <representation name="List" editMode="notEdit"> </representation> <representation name="Card" editMode="edit" stdFilter.isAvailable="false"> <layout> <simpleComposer> <frame filter.isVisible="false"> <card/> </frame> </simpleComposer> </layout> </representation> <representation name="Lookup" editMode="notEdit"> </representation> </view> ``` ## Пользовательская блокировка Пользовательская блокировка позволяет блокировать бизнес-объект РІРЅРµ транзакции базы данных. Такая блокировка работает РІ разрезе пользовательского сеанса Рё даёт возможность пользователю сразу узнать Рѕ блокировке, Р° РЅРµ столкнуться СЃ этим РїСЂРё попытке сохранения изменений. Рлементы заблокированного бизнес-объекта РЅРµ РјРѕРіСѓС‚ быть изменены каким-либо РґСЂСѓРіРёРј пользовательским сеансом. Пользовательскую блокировку можно снять, РїСЂРё этом РІСЃРµ заблокированные сессией объекты становятся доступны для блокирования. ### Встроенная пользовательская блокировка Пользовательская блокировка включается РїСЂРё взаимодействии пользователя СЃ интерфейсом РІ методе `Dvi#beforeEdit`, который является результатом кодогенератора. ```scala override def beforeEdit(): Unit = { ... val rop = defaultRep.thisRop() if (rop != null && (Set(ReadRopMode, UpdateRopMode) contains rop.ropMode)) { defaultRep.tryUserLock() } ... } ``` ### lockObject(gid) ```scala Btk_FormSessionApi().lockObject(gid) ``` Установка пользовательской блокировки для документа, gid которого передан РІ параметр. Р’ системное поле `idlockunit_dz` документа, будет установлен номер блокировки, выданный сессии пользователя, СЃ которой вызван метод. Сессия пользователя представляет запись РІ таблице `Btk_FormSession`. Р’ случае, если документ заблокирован какой-то пользовательской сессией Рё выполняется попытка заблокировать СЃ РґСЂСѓРіРѕР№ сессии, то метод вызовет исключение СЃ описанием блокировки. РџСЂРё попытке редактировать коллекцию заблокированного документа также сработает пользовательская блокировка. Потому что РїСЂРё изменении коллекции beforeEdit() вызывает пользовательскую блокировку для мастер-документа, который заблокирован. Таким образом осуществляется блокировка всего бизнес-объекта. ### lockObjectMulti(gida) ```scala Btk_FormSessionApi().lockObjectMulti(Seq[NGid], riseError = true) ``` Позволяет РѕРґРЅРѕР№ пользовательской сессии заблокировать несколько записей Р·Р° РѕРґРЅСѓ транзакцию РІ БД. Принцип такой же, как Сѓ метода `lockObject(gid)`, РЅРѕ запрос для блокировки вызывается РЅРµ отдельно для каждого документа, Р° собирается для всех документов Рё выполняется 1 раз, С‚.Рµ. Р·Р° РѕРґРЅСѓ транзакцию РІ БД. Можно передавать gid'С‹ различных классов. Поле `riseError` - нужно ли поднимать исключение РїСЂРё наличии заблокированных записей РґСЂСѓРіРѕР№ сессией. Выдаст исключение, если хоть РѕРґРёРЅ РёР· переданных документов уже заблокирован. ```scala Btk_FormSessionApi().lockObjectMulti(Seq[NGid]) //выдаст исключение //проигнорирует уже заблокированные документы Btk_FormSessionApi().lockObjectMulti(Seq[NGid], riseError = false) ``` ### lockObjectMultiWithInfErr(gida) ```scala Btk_FormSessionApi().lockObjectMultiWithInfErr(Seq[NGid]) ``` Данный метод отличается РѕС‚ `Btk_FormSessionApi().lockObjectMulti(Seq[NGid])` тем, что РЅРµ вызывает исключение Рё возвращает информацию Рѕ результате метода. Метод возвращает кортеж: `(Seq[NGid], NString)` `(Seq[NGid] - gid'С‹ уже заблокированных записей РґСЂСѓРіРѕР№ сессией, NString - сформированная ошибка)` Данные можно использовать для более сложной логики