Как исправить ошибку при программном расчете высоты шапки отчета и обходе структуры СКД

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

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

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

Анализ первой ошибки: «Метод объекта не обнаружен (Свойство)»

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


Если Группировки.Свойство("Структура") тогда
    // Код обхода
КонецЕсли;

При выполнении этого кода система выбрасывает исключение. Выясним причину: переменная Группировки, полученная из КомпоновщикНастроек.Настройки.Структура, имеет тип КоллекцияЭлементовСтруктурыНастроекКомпоновкиДанных. В отличие от стандартного объекта 1С типа Структура, у данной коллекции нет метода Свойство().

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

Проблема бесконечного цикла при обходе коллекции

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


Группировки = КомпоновщикНастроек.Настройки.Структура;
Пока Группировки.Количество() > 0 Цикл
    чШапка = чШапка + 1;
    // Ошибка: состояние переменной Группировки не меняется
КонецЦикла;

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

Решение через правильную итерацию (цикл «Для»)

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


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

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

Рекурсивный метод определения глубины шапки

Наиболее профессиональным способом решения задачи является создание рекурсивной функции. Она будет «спускаться» по дереву группировок и возвращать максимальный уровень вложенности. Рассмотрим, как это можно реализовать.

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

Пример функции для расчета глубины:


Функция ПолучитьМаксимальнуюГлубину(КоллекцияЭлементов)
    МаксГлубина = 0;
    Для Каждого Элемент Из КоллекцияЭлементов Цикл
        ТекущаяГлубина = 1;
        // Проверяем наличие вложенной структуры (для обычных группировок)
        Если ТипЗнч(Элемент) = Тип("ГруппировкаКомпоновкиДанных") И Элемент.Структура.Количество() > 0 Тогда
            ТекущаяГлубина = ТекущаяГлубина + ПолучитьМаксимальнуюГлубину(Элемент.Структура);
        // Для таблиц логика сложнее: нужно проверять и строки, и колонки
        ИначеЕсли ТипЗнч(Элемент) = Тип("ТаблицаКомпоновкиДанных") Тогда
             // Здесь можно добавить логику обхода Элемент.Строки и Элемент.Колонки
        КонецЕсли;
        
        Если ТекущаяГлубина > МаксГлубина Тогда
            МаксГлубина = ТекущаяГлубина;
        КонецЕсли;
    КонецЦикла;
    Возврат МаксГлубина;
КонецФункции

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

Особенности работы с таблицами в СКД

Важно помнить, что если в структуре отчета используется объект ТаблицаКомпоновкиДанных, то расчет высоты шапки усложняется. В таблице есть Строки и Колонки. Высота шапки в этом случае напрямую зависит от количества уровней вложенности именно в Колонках.

Выясним причину: группировки строк уходят «вниз» и не влияют на высоту шапки, в то время как каждая вложенная группировка колонок создает дополнительный «этаж» в заголовке отчета. Поэтому при обходе структуры обязательно используйте проверку ТипЗнч(Элемент). Если вы встретили таблицу, анализировать нужно коллекцию Элемент.Колонки.

Практические советы по отладке

  1. Используйте отладчик: Перед написанием цикла обхода, поставьте точку останова на строке Группировки = КомпоновщикНастроек.Настройки.Структура. В табло отладки посмотрите тип переменной и доступные свойства.
  2. Проверка на пустые настройки: Всегда учитывайте, что пользователь мог не настроить ни одной группировки. Код должен корректно обрабатывать ситуацию, когда Количество() = 0.
  3. Управляемые формы: Если код выполняется в модуле формы, убедитесь, что вы обращаетесь к Отчет.КомпоновщикНастроек.Настройки (или через переменную ЭтаФорма), так как контекст может отличаться в зависимости от места вызова.

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

← На главную