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