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