Как зафиксировать строки и колонки в отчете на СКД

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

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

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

Причины ошибок при программном выводе СКД

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

  1. Ошибка синтаксиса при вызове функций общих модулей в вычисляемых полях или ресурсах. При программной инициализации процессора компоновки данных платформа по умолчанию запрещает выполнение внешних функций в выражениях СКД в целях безопасности. В результате формируется синтаксическая ошибка вида Синтаксическая ошибка ОбщийМодуль.ИмяФункции.
  2. Смещение фиксированной области при изменении состава отборов и параметров. Если жестко указать номер строки (например, ДокументРезультат.ФиксацияСверху = 9;), то при включении или отключении пользователем вывода заголовка, параметров и отборов шапка таблицы будет съезжать относительно линии фиксации.

Рассмотрим, как правильно обойти эти ограничения.

Решение проблемы вызова функций общих модулей

Проанализируем инициализацию объекта ПроцессорКомпоновкиДанных. Метод Инициализировать() принимает несколько параметров:

  1. МакетКомпоновки — скомпонованный макет;
  2. ВнешниеНаборыДанных — коллекция внешних таблиц (если используются);
  3. ДанныеРасшифровки — объект данных расшифровки;
  4. ВозможностьИспользованияВнешнихФункций — булево значение.

Если в схеме компоновки данных применяются вызовы функций из общих модулей (с установленным свойством «Сервер»), четвертый параметр необходимо обязательно передавать как Истина.

Посмотрим на пример корректной инициализации:


ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки, Истина);

Также важно убедиться, что вызываемый общий модуль имеет флаг «Вызов сервера» или доступен в контексте выполнения компоновки.

Способ 1. Поэлементный вывод с автоматическим определением границы шапки

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

Разберем готовый алгоритм в процедуре ПриКомпоновкеРезультата модуля отчета:


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

Способ 2. Упрощенная компоновка и поиск заголовка таблицы

Вместо ручного создания всей цепочки объектов компоновки данных можно использовать стандартный платформенный метод СкомпоноватьРезультат(). Он автоматически инициализирует окружение и позволяет функциям модулей выполняться без дополнительных параметров.

После вывода отчета точную строку для фиксации можно найти с помощью метода НайтиТекст() по названию одной из ключевых колонок шапки. Рассмотрим этот подход:


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

Различие фиксации на экране и при печати

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

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


// Указываем диапазон строк для повторения на каждом листе при печати
ДокументРезультат.ПовторятьПриПечатиСтроки = ДокументРезультат.Область(1, , ДокументРезультат.ФиксацияСверху, );

Применение этих правил позволяет сформировать удобный для пользователя интерфейс отчета, защищенный от сбоев при изменении настроек отборов и состава колонок.

← На главную