Разработка и Конфигурация · 10 мин
Как заполнить дерево значений в 1С на обычных формах
Практическое руководство по заполнению дерева значений в 1С на обычных формах: создание колонок, добавление строк, иерархия, вывод на форму и типичные ошибки.
Дерево значений в 1С — иерархическая структура данных, которая используется для отображения вложенных списков: групп номенклатуры, структуры организации, разделов документов. В обычных формах работа с деревом имеет свои особенности: данные хранятся в реквизите формы типа «ДеревоЗначений», а отображаются через элемент формы «ТабличноеПоле» с установленным свойством «Дерево».
Заполнение дерева выполняется программно на встроенном языке. Разработчик создаёт колонки, добавляет строки верхнего уровня, а затем для каждой строки может добавить подчинённые строки через коллекцию «Строки». Такая модель позволяет строить иерархию любой глубины и заполнять её как из запроса, так и из произвольных данных.
Ниже разобран полный цикл работы: от создания реквизита и колонок до вывода дерева на форму, обхода строк и типичных ошибок, которые встречаются при реализации.
Создание реквизита и колонок дерева
Первый шаг — добавить в форму реквизит типа «ДеревоЗначений». В конфигураторе откройте форму, перейдите на закладку «Реквизиты» и добавьте реквизит, например с именем «ДеревоНоменклатуры». Тип выберите «ДеревоЗначений». Если реквизит создаётся программно, используется метод ИзменитьРеквизиты() либо дерево объявляется как переменная модуля формы.
Далее нужно определить состав колонок. Без колонок дерево не сможет хранить данные — каждая добавляемая строка будет пустой. Колонки добавляются методом Добавить() коллекции Колонки:
Дерево = Новый ДеревоЗначений;
Дерево.Колонки.Добавить("Наименование", Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(150)));
Дерево.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 3)));
Дерево.Колонки.Добавить("Ссылка");
Третья колонка объявлена без типа — она сможет хранить значения любого типа, например ссылки на элементы справочника. Указывать точные типы полезно для контроля данных и корректного отображения, но для служебных колонок со ссылками составной тип допустим.
Добавление строк и построение иерархии
Строки верхнего уровня добавляются методом Добавить() коллекции Строки самого дерева. Метод возвращает объект «СтрокаДереваЗначений», у которого есть собственная коллекция Строки — через неё добавляются подчинённые строки:
СтрокаГруппа = Дерево.Строки.Добавить();
СтрокаГруппа.Наименование = "Материалы";
СтрокаЭлемент = СтрокаГруппа.Строки.Добавить();
СтрокаЭлемент.Наименование = "Стальной лист";
СтрокаЭлемент.Количество = 12.5;
Глубина вложенности не ограничена: у строки второго уровня так же есть коллекция Строки, и иерархию можно продолжать. На практике деревья глубже 4–5 уровней становятся неудобными для пользователя, поэтому при проектировании интерфейса стоит оценивать читаемость.
Для удаления строк используются методы Удалить() (по конкретной строке) и Очистить() коллекции Строки. Перед повторным заполнением дерева всегда вызывайте Дерево.Строки.Очистить() — иначе при каждом обновлении данные будут дублироваться.
Заполнение дерева из запроса с иерархией
Самый частый сценарий — вывести иерархический справочник, например номенклатуру с группами. Запрос с итогами по иерархии позволяет получить данные уже в виде дерева:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Ссылка,
| Номенклатура.Наименование КАК Наименование
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| НЕ Номенклатура.ПометкаУдаления
|ИТОГИ ПО
| Ссылка ИЕРАРХИЯ";
РезультатЗапроса = Запрос.Выполнить();
Дерево = РезультатЗапроса.Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией);
Метод Выгрузить() с параметром «ПоГруппировкамСИерархией» возвращает готовое дерево значений, где строки групп содержат вложенные элементы. Это самый быстрый способ получить иерархию без ручного перебора. Колонки результата будут соответствовать полям запроса.
Альтернатива — ручное построение: выгрузить плоскую таблицу с колонкой «Родитель» и рекурсивно распределить строки по веткам. Такой подход нужен, когда структура запроса не позволяет использовать итоги по иерархии или данные приходят из нескольких источников.
- 1Создайте реквизит формы типа «ДеревоЗначений» и табличное поле, связанное с ним
- 2Сформируйте запрос с ИТОГИ ПО Ссылка ИЕРАРХИЯ
- 3Выгрузите результат методом Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией)
- 4Присвойте полученное дерево реквизиту формы или скопируйте строки
- 5Вызовите ЭлементыФормы.Дерево.СоздатьКолонки() или настройте колонки вручную
- 6Проверьте отображение: группы должны раскрываться, данные — совпадать со справочником
Вывод дерева на обычную форму
Чтобы пользователь увидел дерево, на форму добавляется элемент «ТабличноеПоле». В палитре свойств укажите путь к данным — реквизит типа «ДеревоЗначений». После этого платформа автоматически включит режим дерева: появятся пиктограммы раскрытия и сворачивания веток.
Если колонки дерева создаются программно, табличное поле нужно обновить методом СоздатьКолонки() — он сформирует колонки элемента формы по составу колонок данных. При статичной структуре проще один раз настроить колонки в конфигураторе, указав для каждой путь к данным (имя колонки дерева).
Для удобства пользователя полезно развернуть дерево программно. Метод Развернуть() табличного поля раскрывает конкретную строку, а перебор строк верхнего уровня с вызовом Развернуть для каждой даст полностью раскрытое дерево. Для больших деревьев (тысячи строк) полное разворачивание может заметно замедлить открытие формы — в этом случае разворачивайте только первый уровень.
Если после присвоения дерева реквизиту форма показывает пустое поле, чаще всего причина в том, что табличное поле ссылается на другой реквизит или колонки не созданы. Проверьте свойство «Данные» табличного поля и вызовите СоздатьКолонки() после заполнения.
Обход и поиск строк дерева
После заполнения часто требуется найти строку по значению или обработать все ветки. Для поиска на текущем уровне используется метод Найти() коллекции строк: Дерево.Строки.Найти(ИскомоеЗначение, "Наименование", Истина). Третий параметр «Истина» включает поиск по всем уровням иерархии, а не только по строкам верхнего уровня.
Полный обход дерева выполняется рекурсивной процедурой:
Процедура ОбойтиДерево(Строки)
Для Каждого Строка Из Строки Цикл
// обработка строки
ОбойтиДерево(Строка.Строки);
КонецЦикла;
КонецПроцедуры;
У каждой строки есть свойство Родитель, позволяющее подняться на уровень выше, и метод Уровень(), возвращающий глубину вложенности (0 — верхний уровень). Это удобно для отступов, проверок логики и условного оформления.
Типичные ошибки и ограничения
Наиболее частая проблема — потеря данных при передаче дерева между клиентом и сервером. В обычных формах код выполняется в основном на клиенте, но если логика вынесена в серверные вызовы, помните: дерево значений сериализуется, однако большие деревья создают заметный трафик. Для тяжёлых структур лучше готовить данные на сервере целиком и передавать один раз.
Вторая группа ошибок связана с изменением структуры: добавление колонок после заполнения, очистка дерева без очистки табличного поля, обращение к строкам по индексу после удаления элементов. Индексы в коллекции сдвигаются после удаления — используйте обход «с конца» или ищите строки по значению.
Проверка результата
После реализации проверьте дерево на контрольном примере: выберите справочник с известной структурой, сравните количество групп и элементов в дереве и в списке справочника. Убедитесь, что помеченные на удаление элементы отфильтрованы, если это требуется логикой.
Как проверить результат
Группы и вложенность совпадают со справочником-источником
Элементы лежат на верхнем уровне или группы пустые
После повторного заполнения количество строк не меняется
Строки дублируются — пропущена очистка
Ветки раскрываются, значения колонок видны
Пустое табличное поле или колонки без данных
Полезно также проверить поведение при пустом источнике данных: форма должна корректно показать пустое дерево без ошибок обращения к строкам. Обработку таких ситуаций стоит предусмотреть явно — проверкой РезультатЗапроса.Пустой до выгрузки.
Что важно запомнить
Дерево значений заполняется через колонки и вложенные коллекции Строки; быстрее всего получить иерархию — запросом с ИТОГИ ПО ... ИЕРАРХИЯ и выгрузкой в режиме ПоГруппировкамСИерархией. Перед повторным заполнением очищайте строки, после программного создания колонок вызывайте СоздатьКолонки() у табличного поля, а большие деревья не разворачивайте целиком.
Частые вопросы
Чем дерево значений отличается от таблицы значений?
Таблица значений — плоская структура из строк и колонок. Дерево значений дополнительно хранит иерархию: у каждой строки есть коллекция подчинённых строк, свойство Родитель и уровень вложенности. Для отображения списков без группировок достаточно таблицы, для вложенных структур нужно дерево.
Как скопировать одно дерево значений в другое?
Используйте сериализацию через ЗначениеВСтрокуВнутр() и обратно, либо метод Скопировать() у объекта дерева: НовоеДерево = СтароеДерево.Скопировать(). Метод создаёт полную копию со всеми уровнями вложенности и значениями колонок.
Почему запрос с итогами выгружается плоской таблицей, а не деревом?
Метод Выгрузить() по умолчанию использует обход «ПоГруппировкам», который даёт таблицу значений. Чтобы получить дерево, передайте параметр ОбходРезультатаЗапроса.ПоГруппировкамСИерархией и убедитесь, что в запросе указано ИТОГИ ПО полю с ключевым словом ИЕРАРХИЯ.
Как развернуть все ветки дерева на форме программно?
Переберите строки верхнего уровня и для каждой вызовите ЭлементыФормы.ИмяПоля.Развернуть(Строка, Истина) — второй параметр включает рекурсивное раскрытие подчинённых веток. Для больших деревьев это может занять заметное время, поэтому часто разворачивают только первый уровень.
Можно ли редактировать данные прямо в дереве на форме?
Да, табличное поле с деревом поддерживает интерактивное редактирование, если не снято свойство «ТолькоПросмотр». Пользователь может изменять значения ячеек и добавлять строки. Учтите, что вложенные строки добавляются в текущую ветку — уровень вложенности определяется позицией курсора.
Как найти все строки дерева по условию, а не только первую?
Метод НайтиСтроки() с отбором ищет только на одном уровне. Для поиска по всему дереву напишите рекурсивную процедуру обхода с проверкой условия и добавлением подходящих строк в массив или таблицу результатов.