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