Как правильно реализовать цикл для вывода вертикальных и горизонтальных областей (шахматки) в табличный документ 1С?

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

При разработке отчетов и печатных форм в среде 1С:Предприятие часто возникает задача вывода динамических таблиц, у которых заранее неизвестно количество не только строк, но и колонок. Такие таблицы в практике разработки называют кросс-таблицами, матрицами или шахматками. Типичный пример — отчет по продажам, где в строках выводятся товары, а в колонках — дни месяца или склады компании.

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

Понимание работы методов Вывести() и Присоединить()

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

  1. Вывести(Область) — этот метод берет указанную область макета и выводит ее в табличный документ всегда с новой строки. При этом каретка позиционируется в крайнее левое положение (колонка №1) новой строки, а все последующие вызовы этого метода будут сдвигать каретку еще ниже.
  2. Присоединить(Область) — этот метод выводит указанную область в той же строке, в которой был произведен предыдущий вывод. Каретка смещается вправо, непосредственно за границу последней выведенной ячейки. Метод незаменим для динамического добавления колонок.

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

Ключевое понятие: Пересечение областей ("Строка|Колонка")

Когда мы разрабатываем макет (MXL) для кросс-таблицы, мы не можем просто нарисовать статичную таблицу. Нам нужно разделить макет на именованные секции по двум осям:

Чтобы программно заполнить и вывести ячейку, которая находится на пересечении конкретной строки и конкретной колонки, в 1С используется специальный синтаксис с вертикальной чертой |. Мы обращаемся к макету и получаем пересечение двух областей:

ОбластьЯчейки = Макет.ПолучитьОбласть("СтрокаДанных|КолонкаДанных");

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

Пошаговый алгоритм и готовый шаблон кода для вывода кросс-таблицы

Рассмотрим подробнее классический шаблон построения кросс-таблицы. Нам понадобятся два массива (или другие коллекции данных, например, результаты запроса): один с элементами строк, другой — с элементами колонок.


// Создаем результирующий табличный документ
ТабДок = Новый ТабличныйДокумент;

// Получаем макет обработки или отчета
Макет = ПолучитьМакет("ИмяМакета");

// Шаг 1. ВЫВОД ШАПКИ ТАБЛИЦЫ
// Выводим левый верхний угол (пересечение шапки строк и шапки колонок)
ОбластьШапкаЛево = Макет.ПолучитьОбласть("Шапка|СтрокаЗаголовок");
ТабДок.Вывести(ОбластьШапкаЛево);

// В цикле присоединяем заголовки колонок в этой же строке
Для Каждого ТекущаяКолонка Из МассивКолонок Цикл
    ОбластьШапкаКолонка = Макет.ПолучитьОбласть("Шапка|КолонкаДанных");
    ОбластьШапкаКолонка.Параметры.ИмяКолонки = ТекущаяКолонка.Представление;
    ТабДок.Присоединить(ОбластьШапкаКолонка);
КонецЦикла;

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

Важные нюансы и подводные камни при ручном выводе макетов

При программном формировании динамических отчетов разработчики часто сталкиваются с неочевидным поведением платформы. Выясним основные причины проблем и способы их решения:

1. Обязательный вывод пустых областей. Если в вашей матрице на пересечении определенной строки и колонки нет данных (например, товар не продавался в этот день), вы все равно обязаны выполнить метод ТабДок.Присоединить(ОбластьЯчейки), предварительно очистив или передав пустое значение в параметр. Если этого не сделать и пропустить вызов метода для пустой ячейки, то следующая заполненная ячейка «прилипнет» левее, сместив всю сетку данных. Визуально таблица будет полностью разрушена.

2. Искажение ширины колонок и метод СоздатьФорматСтрок(). Когда вы программно выводите разные вертикальные области, 1С пытается автоматически сопоставить их ширину. Из-за этого колонки в разных строках могут начать растягиваться или сжиматься по ширине самого длинного элемента. Чтобы у каждой строки табличного документа была своя собственная, независимая сетка ширины колонок, обязательно используйте встроенный метод:

ТабДок.СоздатьФорматСтрок();

Этот метод рекомендуется вызывать в самом конце формирования табличного документа, перед его отображением пользователю или выводом на печать.

Альтернатива: Почему СКД (Система компоновки данных) эффективнее

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

В современных конфигурациях 1С для решения таких задач настоятельно рекомендуется использовать Систему компоновки данных (СКД). Нам достаточно:

  1. Написать простой запрос, получающий плоскую таблицу данных.
  2. В настройках структуры отчета добавить элемент типа «Таблица».
  3. В строки таблицы перетащить поле, отвечающее за строки (например, Номенклатура).
  4. В колонки таблицы перетащить поле, отвечающее за колонки (например, Период или Склад).
  5. В ресурсы добавить суммируемое поле (например, Количество).

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

← На главную