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

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

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

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

Метод 1: Рекурсивный обход структуры настроек СКД

Основная причина, по которой поле остается в отчете, заключается в том, что структура СКД иерархична. Настройки выбора могут быть переопределены внутри каждой группировки. Чтобы полностью исключить поле, нам необходимо проанализировать объект Структура в настройках компоновки. Рассмотрим алгоритм, который позволяет найти и отключить использование поля во всех элементах структуры (группировках, строках и колонках таблиц).

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


// Основная процедура для инициализации процесса скрытия полей
Процедура СкрытьПоляВНастройках(КомпоновщикНастроек, МассивИменПолей)
    
    Настройки = КомпоновщикНастроек.Настройки;
    
    // Формируем массив объектов ПолеКомпоновкиДанных
    МассивПолей = Новый Массив;
    Для Каждого ИмяПоля Из МассивИменПолей Цикл
        МассивПолей.Добавить(Новый ПолеКомпоновкиДанных(ИмяПоля));
    КонецЦикла;

    // 1. Отключаем в общих выбранных полях (корневой уровень)
    ОтключитьПоляВКоллекцииВыбора(Настройки.Выбор.Элементы, МассивПолей);
    
    // 2. Запускаем рекурсивный обход структуры
    ОбходСтруктурыНастроекРекурсивно(Настройки.Структура, МассивПолей);
    
КонецПроцедуры

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

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

Важный момент: Мы используем свойство Использование = Ложь вместо физического удаления элемента из коллекции. Это более безопасный метод, так как он не нарушает индексы коллекции во время обхода и позволяет легко вернуть видимость поля при необходимости.

Метод 2: Использование функциональных опций

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

Метод 3: Постобработка табличного документа

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

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


// Пример удаления области в табличном документе
ОбластьДляУдаления = Результат.НайтиТекст("ИмяНенужнойКолонки");
Если ОбластьДляУдаления <> Неопределено Тогда
    НомерКолонки = ОбластьДляУдаления.Лево;
    Результат.УдалитьОбласть(Результат.Область(, НомерКолонки, , НомерКолонки), ТипСмещенияТабличногоДокумента.ПоГоризонтали);
КонецЕсли;

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

Работа с пользовательскими настройками

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

Выясним, как гарантированно отключить видимость через пользовательские настройки. Для этого нам нужно найти элемент в КомпоновщикНастроек.ПользовательскиеНастройки.Элементы, идентификатор которого совпадает с ИдентификаторПользовательскойНастройки соответствующего поля выбора. Если мы программно устанавливаем Использование = Ложь на уровне настроек, убедитесь, что этот идентификатор пуст или что вы также обновили коллекцию пользовательских настроек.

Резюме и рекомендации

Подводя итог, разберем по шагам наиболее эффективную стратегию:

  1. Определите момент изменения: Лучше всего выполнять манипуляции с колонками в процедуре ПриКомпоновкеРезультата в модуле объекта отчета. Это позволит изменениям вступить в силу непосредственно перед генерацией данных.
  2. Используйте рекурсию: Для отчетов со сложной структурой всегда обходите не только Выбор основного уровня, но и вложенные элементы Структуры.
  3. Предпочитайте свойство Использование: Вместо удаления полей из коллекции, просто отключайте их флаг видимости. Это сохранит работоспособность отчета, если на это поле завязаны другие расчетные механизмы.
  4. Проверяйте Автополя: Если в группировках используются Автополя, достаточно отключить видимость поля на родительском уровне. Если же поля в группировках прописаны явно — используйте Метод 1.

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

← На главную