Отображение дерева значений в таблице формы – задача на первый взгляд простая, но на практике не такая уж и тривиальная – даже у матерых разработчиков она, порой, вызывает сложности.
В статье на учебном, но вполне прикладном примере, разберем следующие действия:
- Разместим таблицу на форме и подготовим ее к приему иерархических данных.
- Получим выставленные счета за период с группировкой по контрагентам.
- Выгрузим данные из запроса в таблицу с иерархией в виде дерева.
- Бонусом сделаем так, чтобы пользователь мог сворачивать и разворачивать дерево, а также отмечать нужные элементы в нем для последующей обработки.
Для разработки данного примера будем использовать типовую конфигурацию Бухгалтерия предприятия, редакция 3.0 (3.0.135.22)
Также изучим и будем использовать функции и процедуры библиотеки стандартных подсистем БСП, подходящие под нашу задачу.
Нам потребуется новая внешняя обработка. Создаем ее и поехали!
Размещаем дерево значений на управляемой форме
Идем в реквизиты формы и создаем новый элемент типа «Дерево значений». Сам реквизит так и назовем «Дерево».
Внутри дерева нам понадобятся следующие колонки:
- Флаг – Тип: булево – с помощью него пользователь будет отмечать нужные элементы
- Контрагент – Тип: СправочникСсылка.Контрагенты
- Документ – Тип: ДокументСсылка.СчетНаОплатуПокупателю
Превратим дерево в таблицу – для этого перетащим его мышкой на форму. Под словом «превратим» надо понимать, что после помещения на форму дерево предстает перед нами в форме таблицы, хранящей в себе данные типа «ДеревоЗначений».
В тоже время тип реквизита «Дерева» может быть также «ТаблицаЗначений» - это полезно просто понимать, но для нашей задачи не нужно.
Для красоты сделаем в таблице следующее:
- Уберем из состава команд «Добавить», «Скопировать» и «Изменить». Чтобы пользователи не портили получаемые для обработки данные, эти действия должны быть заблокированы.
- Снимем признак для свойства «ИзменятьПорядокСтрок». В контексте нашей задачи, это действие освободит пользователя от бессмысленных действий и скроет лишние кнопки на форме.
В итоге получим такой вид нашей таблицы:
На данном этапе уже все готово для приема данных из запроса.
Но я хочу, чтобы вы обратили внимание на следующие важные свойства элементов таблицы – зачастую эти детали могут застопорить разработку и отнять ваше время:
Чтобы флаг отображался как флаг (галочка) нужно проверить, чтобы у соответствующей колонки свойство «Вид» имело значение «Поле флажка»
Если это свойство будет установлено в какое-либо другое значение, то вы можете получить неожиданные результаты.
У таблицы есть свойство «Отображение», которое может принимать значения «Список», «Иерархический список», «Дерево». Распространенная ошибка заключается в установке этого свойства в значение «Дерево». Если при этом таблица хранит в себе реквизит типа «ТаблицаЗначений», - а не дерево! – то ожидать от нее поведения, характерного для дерева, такого как сворачивание-разворачивание группировок, не стоит. Как работает это свойство и чего от него стоит ожидать мы увидим далее. В нашем случае это свойство установлено правильно по умолчанию.
Идем далее.
Получаем счета за период с группировкой по контрагентам
Получать будем, конечно же запросом. В запросе нам понадобятся те же самые поля, которые мы определили для нашего дерева, т.е. «Флаг», «Контрагент» и «Документ».
Но сначала создадим команду и вынесем ее на командную панель таблицы «Дерево». Команду назовем «Заполнить».
Также подготовим даты, необходимые нам для выборки счетов

Теперь создадим процедуры на клиенте и сервере и привяжем клиентскую процедуру к команде «Заполнить». Текст запроса будем размещать в серверной процедуре. Он будет таким:
Запрос = Новый Запрос; Запрос.Текст = "ВЫБРАТЬ | ИСТИНА КАК Флаг, | СчетНаОплатуПокупателю.Контрагент КАК Контрагент, | СчетНаОплатуПокупателю.Ссылка КАК Документ |ИЗ | Документ.СчетНаОплатуПокупателю КАК СчетНаОплатуПокупателю |ГДЕ | СчетНаОплатуПокупателю.Дата МЕЖДУ &ДатаНач И &ДатаКон | |УПОРЯДОЧИТЬ ПО | СчетНаОплатуПокупателю.Контрагент.Наименование, | СчетНаОплатуПокупателю.Дата |ИТОГИ // Чтобы получилось дерево, в запросе обязательно должны быть итоги! | ИСТИНА КАК Флаг |ПО | Контрагент";
Обратите внимание! Чтобы на выходе из запроса у нас получилось дерево, нужно выполнить 2 обязательных условия:
- Использовать директиву «ИТОГИ» в тексте запроса. Именно благодаря итогам формируется иерархия дерева. В нашем случае нужны итоги по полю «Контрагент», а в качестве суммируемого поля выступает «Флаг».
- Чтобы выгрузка из результата запроса была сформирована с обходом типа «ПоГруппировкам». В нашем случае используется конструкция:
РезультатЗапроса = Запрос.Выполнить().Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); // Выгрузка в дерево значений!
Выгружаем данные из запроса в таблицу с иерархией в виде дерева
Нам осталось вывести данные из запроса на экран пользователю. Для этого передадим в запрос выбранные даты, выполним его и осуществим выгрузку результата на форму. Код будет таким:
Запрос.УстановитьПараметр("ДатаНач", НачалоДня(ДатаНач)); ДатаОкончания = ДатаКон; Если ДатаОкончания = Дата(1, 1, 1, 0, 0, 0) Тогда ДатаОкончания = Дата(3999, 12, 31); // бесконечно большая дата КонецЕсли; Запрос.УстановитьПараметр("ДатаКон", КонецДня(ДатаОкончания)); РезультатЗапроса = Запрос.Выполнить().Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); // Выгрузка в дерево значений! // Выгрузка результата запроса в дерево КоллекцияЭлементовДерева = Дерево.ПолучитьЭлементы(); КоллекцияЭлементовДерева.Очистить(); ОбщегоНазначения.ЗаполнитьКоллекциюЭлементовДереваДанныхФормы(КоллекцияЭлементовДерева, РезультатЗапроса);
Как вы заметили, формирование дерева на форме при помощи типовой функции БСП занимает всего 3 строки кода.
В первой строке мы получаем строки дерева верхнего уровня типа «ДанныеФормыКоллекцияЭлементовДерева». Второй строкой очищаем их. А третьей – заполняем типовой процедурой, встроенной в конфигурацию.
Разбирать саму процедуру я не буду – при желании можно сделать это самостоятельно, обратившись к модулю конфигурации «ОбщегоНазначения».
Теперь пора протетсить, что получилось. Для этого сохраним обработку и откроем ее в режиме предприятия. По кнопке «Заполнить» получаем такой результат:

Видно, что дерево сформировалось. Его группировками, как и задумывалось, является контрагент, а в колонке флаг стоит заветная «галочка». С помощью нее пользователь может отмечать, какие счета он хочет подвергнуть дальнейшей обработке.
Реализуем процедуры сворачивания и разворачивания дерева
Чтобы организовать свертку-раскрытие дерева добавим в команды формы соответствующие действия и вынесем их на командную панель таблицы в виде кнопок.
библиотеки.

Теперь пропишем процедуры и привяжем их к командам.
Привожу универсальный код процедур для сворачивания и разворачивания деревьев в любой таблице на управляемых формах, которые вы передадите в параметре.
// ТаблицаФормы: Элементы["ИмяТаблицы"] // где "ИмяТаблицы" - реквизит формы типа "ТаблицаФормы", хранящий значений типа "ДеревоЗначений" Процедура СвернутьДеревоНаФорме(ТаблицаФормы) Если ТипЗнч(ТаблицаФормы) = Тип("ТаблицаФормы") Тогда ДанныеФормыДерево = ЭтаФорма[ТаблицаФормы.Имя]; СтрокиДерева = ДанныеФормыДерево.ПолучитьЭлементы(); Иначе СтрокиДерева = ТаблицаФормы; КонецЕсли; Для каждого СтрокаДерева Из СтрокиДерева Цикл ПодчиненныеСтроки = СтрокаДерева.ПолучитьЭлементы(); Если ПодчиненныеСтроки.Количество() = 0 Тогда Продолжить; КонецЕсли; СвернутьДеревоНаФорме(ПодчиненныеСтроки); ТаблицаФормы.Свернуть(СтрокаДерева.ПолучитьИдентификатор()); КонецЦикла; КонецПроцедуры // ТаблицаФормы: Элементы["ИмяТаблицы"] // где "ИмяТаблицы" - реквизит формы типа "ТаблицаФормы", хранящий значений типа "ДеревоЗначений" Процедура РазвернутьДеревоНаФорме(ТаблицаФормы) ДанныеФормыДерево = ЭтаФорма[ТаблицаФормы.Имя]; Для каждого СтрокаПервогоУровня Из ДанныеФормыДерево.ПолучитьЭлементы() Цикл ТаблицаФормы.Развернуть(СтрокаПервогоУровня.ПолучитьИдентификатор(), Истина); КонецЦикла; КонецПроцедуры Процедура СвернутьДерево(Команда) СвернутьДеревоНаФорме(Элементы.Дерево); КонецПроцедуры Процедура РазвернутьДерево(Команда) РазвернутьДеревоНаФорме(Элементы.Дерево); КонецПроцедуры
Посмотрим на результат разворачивания дерева по кнопке глазами пользователя:

Для добавления комментария необходимо авторизоваться.
Вход | Регистрация