Как правильно заполнить дерево значений в 1С и настроить отображение иерархии?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При проектировании интерфейсов в 1С:Предприятии часто возникает необходимость представить информацию в виде структурированного дерева. Для этих целей используется объект ДеревоЗначений. Однако при его заполнении и выводе на форму начинающие разработчики регулярно сталкиваются с трудностями: подчиненные элементы не отображаются, данные выводятся сплошным плоским списком, или дерево вовсе кажется пустым.

В этой статье мы подробно разберем, как правильно заполнять дерево значений программно (вручную по выборке), как выгружать его напрямую из запроса с итогами, а также как настроить свойства элемента формы для корректного отображения иерархии и сетки границ.

Разбор типичной ошибки: программное добавление подчиненных строк

Рассмотрим ситуацию, когда на форме создано дерево значений с одной колонкой составного типа (например, ГруппировкаНоменклатуры, в которой могут храниться ссылки на справочники НоменклатурнаяГруппа и Номенклатура). Наша задача — сделать так, чтобы номенклатурная группа располагалась на верхнем уровне, а подчиненная ей номенклатура — на втором уровне.

Часто разработчики пишут код следующим образом:


// Ошибочный вариант заполнения
Пока Выборка.Следующий() Цикл
    НС1 = Дерево1.Строки.Добавить();
    НС1.НоменклатурнаяГруппа = Выборка.НоменклатурнаяГруппа;
    
    НС2 = НС1.Строки.Добавить();
    НС2.Номенклатура = Выборка.Номенклатура;
КонецЦикла;

Проанализируем этот код. На первый взгляд, логика соблюдена: мы добавляем строку первого уровня НС1, а затем в ее коллекцию строк добавляем подчиненную строку НС2. Однако при таком подходе в интерфейсе мы увидим только номенклатурные группы, а подчиненные номенклатурные позиции отображаться не будут.

Выясним причину проблемы. Она кроется в именах колонок. В коде значения присваиваются разным свойствам (колонкам): НоменклатурнаяГруппа для родителя и Номенклатура для потомка. Но если на форме у дерева значений создана всего одна колонка (например, с именем Номенклатура), то свойство НоменклатурнаяГруппа у строки дерева просто отсутствует или не связано с элементом формы. Данные записываются "в пустоту", а подчиненная строка отображается пустой.

Чтобы исправить эту ошибку, мы должны заполнять одну и ту же колонку как для родительской, так и для подчиненной строки. Давайте посмотрим на правильный вариант кода:


// Правильный вариант ручного заполнения
Пока Выборка.Следующий() Цикл
    // Создаем строку первого уровня (родительский узел)
    НС1 = Дерево1.Строки.Добавить();
    НС1.Номенклатура = Выборка.НоменклатурнаяГруппа; // Записываем группу в общую колонку
    
    // Создаем строку второго уровня (подчиненный узел)
    НС2 = НС1.Строки.Добавить();
    НС2.Номенклатура = Выборка.Номенклатура; // Записываем номенклатуру в ту же колонку
КонецЦикла;

В данном случае колонка Номенклатура имеет составной тип, что позволяет ей хранить как ссылки на номенклатурные группы, так и ссылки на саму номенклатуру. Заполняя одно и то же поле на разных уровнях иерархии, мы добиваемся корректного распределения данных.

Настройка элемента формы для отображения дерева

Даже после исправления кода в модуле разработчики часто замечают, что дерево на форме все равно отображается плоским списком, либо подчиненные строки видны, но без возможности их свернуть или развернуть. Это связано с настройками элемента формы.

По умолчанию элемент формы типа "Таблица", связанный с деревом значений, может не иметь включенной настройки отображения иерархических связей. Чтобы включить древовидную структуру, выполните следующие шаги в конфигураторе:

  1. Откройте управляемую (или обычную) форму, на которой размещено ваше дерево значений.
  2. Выделите элемент формы типа "Таблица", отображающий ваше дерево.
  3. В панели свойств найдите флажок Отображать иерархию (или свойство ОтображатьИерархию в коде) и установите его в значение Истина.

После включения этого свойства платформа автоматически добавит кнопки свертывания и развертывания узлов (плюсы и минусы) к первой колонке таблицы, и данные примут правильный древовидный вид.

Автоматическое заполнение дерева значений из запроса

Ручной обход выборки в цикле — не самый производительный метод, особенно при больших объемах данных. Гораздо эффективнее использовать возможности механизма запросов платформы 1С. Мы можем построить запрос с итогами и выгрузить его результаты напрямую в дерево значений.

Рассмотрим пример запроса и его выгрузки:


Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ
|    спрНоменклатура.Ссылка КАК Номенклатура,
|    спрНоменклатура.НоменклатурнаяГруппа КАК НоменклатурнаяГруппа
|ИЗ
|    Справочник.Номенклатура КАК спрНоменклатура
|ГДЕ
|    спрНоменклатура.Ссылка В ИЕРАРХИИ(&ГруппыТоваров)
|    И спрНоменклатура.ЭтоГруппа = ЛОЖЬ
|ИТОГИ ПО
|    НоменклатурнаяГруппа";

РезультатЗапроса = Запрос.Выполнить();

// Выгружаем результат запроса в дерево значений по группировкам
ДеревоЗначений = РезультатЗапроса.Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам);

При использовании метода Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам) крайне важно учитывать два нюанса:

  1. Строгое совпадение имен колонок: Колонки создаваемого дерева значений будут иметь ровно те же имена, что и поля в секции ВЫБРАТЬ и секции ИТОГИ ПО вашего запроса. Если на форме колонка называется Номенклатура, а в итогах запроса мы группируем по полю НоменклатурнаяГруппа, то дерево создаст две разные колонки. На уровне группировки (первый уровень) будет заполнено поле НоменклатурнаяГруппа, а поле Номенклатура будет пустым. На детальном уровне (второй уровень) будет заполнено только поле Номенклатура. Это приводит к эффекту "пустых строк" в интерфейсе.
  2. Решение проблемы пустых ячеек: Чтобы данные выгружались корректно в одну колонку, мы можем переименовать поля в запросе или использовать одну составную колонку в дереве, но тогда ручной перенос данных из плоской выборки запроса может быть предпочтительнее.

Отображение границ и линий в таблице дерева

Еще один частый вопрос касается визуального оформления дерева на форме: как сделать границы строк и колонок видимыми, чтобы интерфейс выглядел более структурированным? По умолчанию сетка в таблицах управляемых форм может быть отключена.

Решается это очень просто через палитру свойств элемента формы "Таблица":

Эти простые настройки сделают таблицу более читаемой, четко очертив границы каждой ячейки.

Особенности работы с деревом значений на управляемых формах

В платформе 1С:Предприятие 8.3 при работе с управляемым интерфейсом важно помнить ключевое архитектурное правило: объект ДеревоЗначений существует исключительно на стороне сервера. Мы не можем напрямую передать его на клиент или привязать к элементу формы без специальной трансформации.

Давайте разберем по шагам правильную схему работы в управляемом приложении:

  1. На форме создается реквизит (например, с именем ДеревоДанных) и типом значения ДеревоЗначений.
  2. В элементах формы создается Таблица, путь к данным которой указывает на наш реквизит ДеревоДанных.
  3. Заполнение дерева должно происходить в серверном контексте (процедура &НаСервере).
  4. Для того чтобы заполненный программно объект ДеревоЗначений отобразился в интерфейсе, необходимо использовать метод взаимного преобразования: ЗначениеВРеквизитФормы().

Посмотрим на пример реализации этой схемы в коде модуля управляемой формы:


&НаСервере
Процедура ЗаполнитьДеревоНаСервере()
    
    // 1. Преобразуем реквизит формы в прикладной объект "ДеревоЗначений" для работы с ним на сервере
    ДеревоОбъект = РеквизитФормыВЗначение("ДеревоДанных");
    
    // Очищаем старые данные
    ДеревоОбъект.Строки.Очистить();
    
    // 2. Выполняем запрос для получения данных
    Запрос = Новый Запрос;
    Запрос.Текст = 
    "ВЫБРАТЬ
    |    Номенклатура.Ссылка КАК Номенклатура,
    |    Номенклатура.НоменклатурнаяГруппа КАК НоменклатурнаяГруппа
    |ИЗ
    |    Справочник.Номенклатура КАК Номенклатура
    |ГДЕ
    |    НЕ Номенклатура.ЭтоГруппа";
    
    Выборка = Запрос.Выполнить().Выбрать();
    
    // 3. Заполняем дерево значений вручную
    Пока Выборка.Следующий() Цикл
        // Ищем, создавали ли мы уже строку для этой номенклатурной группы
        РодительскаяСтрока = Неопределено;
        Для Каждого СтрокаГруппы Из ДеревоОбъект.Строки Цикл
            Если СтрокаГруппы.ГруппировкаНоменклатуры = Выборка.НоменклатурнаяГруппа Тогда
                РодительскаяСтрока = СтрокаГруппы;
                Прервать;
            КонецЕсли;
        КонецЦикла;
        
        // Если группы еще нет в дереве, создаем ее
        Если РодительскаяСтрока = Неопределено Тогда
            РодительскаяСтрока = ДеревоОбъект.Строки.Добавить();
            РодительскаяСтрока.ГруппировкаНоменклатуры = Выборка.НоменклатурнаяГруппа;
        КонецЕсли;
        
        // Добавляем подчиненную номенклатуру в найденную/созданную группу
        НоваяСтрока = РодительскаяСтрока.Строки.Добавить();
        НоваяСтрока.ГруппировкаНоменклатуры = Выборка.Номенклатура;
    КонецЦикла;
    
    // 4. Возвращаем измененный объект обратно в реквизит формы для отображения на клиенте
    ЗначениеВРеквизитФормы(ДеревоОбъект, "ДеревоДанных");
    
КонецПроцедуры

В этом примере мы использовали колонку ГруппировкаНоменклатуры, которая имеет составной тип. Обратите внимание на алгоритм поиска дублей родительских строк: перед добавлением новой группы мы проверяем, не была ли она добавлена ранее, чтобы избежать дублирования веток дерева.

Оптимизация работы с большими деревьями (Отложенная загрузка)

Если дерево значений должно содержать тысячи или десятки тысяч строк, полное его заполнение на сервере и последующая передача на клиент через ЗначениеВРеквизитФормы могут вызвать серьезные задержки в работе интерфейса. Пользователь будет наблюдать "зависание" программы.

Для решения этой проблемы опытные разработчики применяют паттерн отложенной загрузки (или Lazy Loading). Идея заключается в следующем:

Такой подход позволяет дереву открываться мгновенно, независимо от общего объема данных в базе, так как детальные записи считываются только по требованию пользователя.

Подводя итог, можно сказать, что успешная работа с деревом значений в 1С складывается из аккуратного сопоставления имен колонок при ручном заполнении или выгрузке запроса, правильного распределения типов данных в составных колонках и точечной настройки свойств отображения интерфейса в конфигураторе.

← На главную