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