Одной из наиболее часто встречающихся задач является выбор ограниченного списка записей из некоторого множества (например: выбор нескольких организаций из справочника; выбор нескольких дел из номенклатуры дел; выбор нескольких населенных пунктов из всего множества населенных пунктов и т.п.)
Сразу оговорюсь: в статье рассматриваются способы выбора, при этом выбранные значения могут храниться как списком - в табличных частях, так и в реквизитах - перечислением через разделитель. Подробно способы хранения выбранных значений в этой статье не рассматриваются.
Итак, задачка не самая редкая и способов её решения существует несколько. Рассмотрим их:
Поля множественного выбора
Один из самых «красивых» способов решения задачи. Вся задача сводится к созданию и настройке на форме поля множественного выбора. Хорошо и подробно о полях множественного выбора написано в статье DIRECTUM 4.9. Поля множественного выбора
Однако использовать данную возможность можно начиная с версии 4.9. В более старых версиях такой возможности нет, поэтому придется использовать один из перечисленных ниже вариантов.
CSelectSQL
Используя функцию CSelectSQL (ПВыборSQL) можно вернуть список выбранных пользователем значений, предварительно загрузив в список для выбора необходимое множество.
Коды выбранных записей можно, допустим, поместить в некоторый строковый реквизит перечисленные через разделитель. Однако заранее необходимо просчитать сколько кодов сможет храниться в реквизите. Иначе может возникнуть ситуация когда, например, в строковый реквизит из 50 символов будут записываться коды 500 записей (плюс разделители), в итоге в реквизит запишутся только первые несколько кодов.
Пример на ISBL:
DELIMITER = ';' & CR
SELECTION_CANCELED = 'НЕУДАЧА: ESC!'
// Определить параметры диалога
WindowTitle = 'Укажите подчиненные наши организации'
OurOrgRefID = ИДТипСпр('НОР')
Query = Format("
select
NameAn
from
MBAnalit
where
Vid = %s";
ArrayOf(OurOrgRefID))
OurOrgs = CreateStringList()
OurOrgs.Delimiter = DELIMITER
// Открываем окно для выбора организаций
ChoiseResult = ПВыборSQL(WindowTitle; Query; DELIMITER; OurOrgs.DelimitedText)
// Если выбор успешно завершен
if ChoiseResult <<>> SELECTION_CANCELED
OurSelectedOrgs = CreateStringList()
foreach OurOrgName in CSubString(ChoiseResult; DELIMITER)
OurSelectedOrgs = AddSubString(OurOrgName; OurOrgs; DELIMITER)
endforeach
endif
Заполнение табличной части из справочника
Если множество значений для выбора являются записями некоторого справочника, то выбирать нужные записи можно прямо из справочника, а затем передать выбранные записи например в табличную часть.
Плюсом данного решения является использование всех возможностей справочников (фильтры, иерархии, like-ввод и т.д.)
Пример на ISBL:
// Получить набор данных справочника "НОР" со всеми записями
Reference = References.НОР.GetComponent()
// Создать View для справочника
RefView = Reference.CreateView(Reference.MainViewCode)
// Установить отображения представления в режиме "Выбор"
RefView.ViewMode = vmSelect
// Разрешить выбор нескольких записей
RefView.MultiSelection = TRUE
RefViewFrom = RefView.MainForm
// Показать форму справочника
RefViewFrom.Show
// Если выбрана хотя бы одна запись
if RefViewFrom.Result == mrOK
// Открыть набор данных перед началом работы
Reference.Open()
Reference.OpenRecord()
// Получить детальный набор данных - таблицу подчиненных организаций
OrgTable = Object.DetailDataSet(1)
// Отключить обновление элементов управления (если записей много - чтоб не мерцало)
OrgTable.DisableControls
FreeException()
ExceptionsOff()
// Создать индикатор
Progress = CreateProgress('Добавление подчиненных организаций'; RefView.SelectedRecordCount; False)
Progress.Show
I = 0
// Занести выбранные записи справочника в таблицу подчин.организаций
while I < RefView.SelectedRecordCount
IDRec = RefView.SelectedRecordsID(I)
RecCode = References.НОР.ObjectInfo(IDRec).Code
// Если выбранной строки нет в таблице подчин.организаций, то вставить её
if not OrgTable.Locate('НашиОрг'; RecCode)
OrgTable.Append
OrgTable.Requisites('НашиОрг').Value = RecCode
endif
I = I + 1
Progress.Next
endwhile
Progress.Hide
// Включить обновление элементов управления
ExceptionsOn()
OrgTable.EnableControls
LastException = GetLastException()
// Если возникло исключение во время отключения обновления элементов управ-я
if not VarIsClear(LastException)
Exit(LastException.Message)
endif
// Закрыть набор данных после работы
Reference.CloseRecord
Reference.Close
endif
DualListDialog
Используя функцию DualListDialog (СоздатьДиалогВыбораИзДвухСписков) можно создать диалог с двумя списками. В один из которых занести множество записей для выбора, а второй список вернёт выбранные пользователем значения.
Пример на ISBL:
// Создать двойной список
DualList = CreateDualListDialog('Выбор организаций')
DualList.Title = 'Выбор организаций'
DualList.AvailableItemsTitle = 'Все организаций'
DualList.SelectedItemsTitle = 'Выбранные организации'
Orgs = CreateReference('НОР')
// Заполнить список выбора значениями
foreach Org in Orgs
DualList.AvailableItems.Add(Org.Requisites('Наименование').Value)
endforeach
// Показать список
DualList.Execute()
// Отобразить выбранные значения списка
EditText(DualList.SelectedItems.Text)
Иерархии
По сути это решение представляет собой модификацию одного из предыдущих решений. Суть заключается в выборе не нескольких значений из списка, а только одного, узлового значения в иерархии. В этом случае не придется хранить весь список значений в таблице или в реквизите через разделители. Достаточно одного родителя, все остальные, дочерние записи можно вычислить.
Минусы: Иерархии появились только в версии 4.8. Использовать решение можно будет только применяя справочники.
Возможно существуют еще способы решения этой задачи, я ничего не упустил?
Заполнение табличной части из справочника
Пример не совсем корректен. Я строчки
переставил сразу после
Reference = References.НОР.GetComponent()
Авторизуйтесь, чтобы написать комментарий