Как вывести результат запроса в Дерево значений на форме 1С и настроить иерархический вывод

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

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

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

Выясняем причину: почему в дереве значений на форме отображается только первая группировка?

Рассмотрим стандартную ситуацию. У нас есть запрос с секцией ИТОГИ ПО, результат которого мы хотим отобразить на форме в виде дерева. Мы написали код обхода выборок, добавили строки в элемент управления, но на форме видим плоскую таблицу, где отображается только самый верхний уровень — «Участок». Кнопки развертывания («плюсики») отсутствуют, и вложенные данные («ТехОперация» и «Паспорт») не видны.

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

Для решения этой проблемы выполним следующие шаги:

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

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

Оптимизация вывода запроса в Дерево значений

Проанализируем исходный код заполнения дерева значений. В нем используется последовательный ручной обход выборки запроса с помощью вложенных циклов Пока ... Следующий() Цикл:


ВыборкаУчасток = ВыборкаПаспорта.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам,"Участок");
Пока ВыборкаУчасток.Следующий() Цикл
    Строка = ДеревоЗначенийУчасток.Строки.Добавить();
    Строка.Наименование = ВыборкаУчасток.Участок;
    ВыборкаТехОперация = ВыборкаУчасток.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам,"Техоперация");
    Пока ВыборкаТехОперация.Следующий() Цикл
        Подстрока = Строка.Строки.Добавить();
        Подстрока.Наименование = ВыборкаТехОперация.ТехОперация;
        ...
    КонецЦикла;
КонецЦикла;

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

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


Функция ПолучитьДеревоПаспортов() Экспорт
    
    Запрос = Новый Запрос;
    Запрос.УстановитьПараметр("ВТ_ПАСПОРТА_ТЗ", Маршрутки);
    
    Запрос.Текст = 
    "ВЫБРАТЬ
    |    втУчастки.Паспорт КАК Паспорт,
    |    втУчастки.ТехОперация КАК ТехОперация,
    |    втУчастки.Участок КАК Участок
    |ИЗ
    |    втУчастки КАК втУчастки
    |ИТОГИ ПО
    |    Участок,
    |    ТехОперация";
    
    РезультатЗапроса = Запрос.Выполнить();
    
    // Выгружаем результат напрямую в дерево значений с сохранением группировок
    ДеревоДанных = РезультатЗапроса.Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам);
    
    Возврат ДеревоДанных;
    
КонецФункрии

Метод Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам) самостоятельно проанализирует секцию ИТОГИ ПО вашего запроса, создаст нужную структуру колонок и автоматически вложит строки детальных записей в соответствующие строки группировок. Это избавляет нас от необходимости писать многострочные вложенные циклы.

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

Если мы разрабатываем решение для управляемого интерфейса (тонкий или веб-клиент), то напрямую присвоить выгруженное дерево значений элементу формы нельзя. Реквизиты управляемой формы имеют специальный тип ДанныеФормыДерево, который на сервере необходимо преобразовывать в прикладной объект ДеревоЗначений и обратно.

Давайте разберем по шагам, как правильно реализовать этот процесс на управляемой форме:


&НаСервере
Процедура СформироватьОтчетНаСервере()
    
    // 1. Получаем дерево значений из базы данных
    ДеревоИзЗапроса = ПолучитьДеревоПаспортов();
    
    // 2. Преобразуем реквизит управляемой формы в объект "ДеревоЗначений"
    ДеревоФормы = РеквизитФормыВЗначение("ДеревоЗначенийУчасток", Тип("ДеревоЗначений"));
    
    // 3. Очищаем старые данные и заполняем структуру
    ДеревоФормы.Строки.Очистить();
    
    // Переносим данные из запроса в реквизит формы
    ЗначениеВРеквизитФормы(ДеревоИзЗапроса, "ДеревоЗначенийУчасток");
    
КонецПроцедуры

Решение сопутствующей задачи: отображение «лупы» (кнопки открытия) в ячейке

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

Некоторые разработчики пытаются решить эту задачу через событие ПриВыводеСтроки (или аналогичные обработчики оформления строки), используя свойство ОформлениеСтроки.Ячейки.ИмяКолонки.ОтображатьФлажок или пытаясь найти там свойства кнопок. Это ошибочный путь. Свойство ОформлениеСтроки отвечает исключительно за визуальный стиль отображения конкретной строки (цвет фона, шрифт, отображение картинок или флажков). Кнопка «лупы» или «троеточия» — это интерактивный элемент управления вводом, и настраивается он для всей колонки в целом.

Рассмотрим, как правильно программно включить отображение кнопки открытия («лупы») в обычной форме 1С:


// Настройка отображения кнопки открытия в модуле обычной формы
Процедура НастроитьКолонкиДерева()
    
    // Получаем колонку "Паспорт" из табличного поля на форме
    КолонкаПаспорт = ЭлементыФормы.ДеревоЗначенийУчасток.Колонки.Паспорт;
    
    // Указываем, что в качестве элемента управления ячейки будет использоваться поле ввода
    КолонкаПаспорт.УстановитьЭлементУправления(Тип("ПолеВвода"));
    
    // Включаем кнопку открытия (лупу) у элемента управления колонки
    КолонкаПаспорт.ЭлементУправления.КнопкаОткрытия = Истина;
    
    // Устанавливаем режим отображения кнопки, чтобы она была видна всегда
    КолонкаПаспорт.ОтображениеКнопкиВыбора = ОтображениеКнопкиВыбора.ОтображатьВсегда;
    
КонецПроцедуры

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


// Привязываем событие "Открытие" к процедуре-обработчику
ЭлементыФормы.ДеревоЗначенийУчасток.Колонки.Паспорт.ЭлементУправления.УстановитьДействие("Открытие", Новый Действие("КолонкаПаспортОткрытие"));

Теперь напишем саму процедуру-обработчик в модуле формы. В ней мы переопределим стандартное поведение платформы, если нам требуется выполнить какую-то особую логику перед открытием значения, либо просто вызовем открытие стандартной формы:


Процедура КолонкаПаспортОткрытие(Элемент, СтандартнаяОбработка)
    
    // Отменяем стандартную обработку открытия платформой, если пишем свою логику
    СтандартнаяОбработка = Ложь;
    
    // Получаем текущие данные строки табличного поля, на которой кликнул пользователь
    ТекущаяСтрока = ЭлементыФормы.ДеревоЗначенийУчасток.ТекущиеДанные;
    
    Если ТекущаяСтрока <> Неопределено Тогда
        // Проверяем, что в колонке действительно содержится ссылка на объект
        Если ЗначениеЗаполнено(ТекущаяСтрока.Паспорт) Тогда
            // Открываем форму значения с помощью глобального метода
            ОткрытьЗначение(ТекущаяСтрока.Паспорт);
        Иначе
            Предупреждение("Поле 'Паспорт' не заполнено!");
        КонецЕсли;
    КонецЕсли;
    
КонецПроцедуры

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

← На главную