Как вывести суммы и данные по горизонтали в макет 1С с помощью Вывести() и Присоединить()

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

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

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

Теоретические основы: как 1С позиционирует ячейки по горизонтали

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

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

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

Проектирование макета: работа с пересечениями областей

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

Рассмотрим по шагам, как правильно разметить макет в конфигураторе:

  1. Создадим горизонтальную именованную строку для шапки отчета и назовем ее Шапка.
  2. Создадим горизонтальную именованную строку для вывода данных и назовем ее Строка.
  3. Создадим вертикальную именованную колонку для фиксированных данных слева (например, для названия контрагента или статьи расходов) и назовем ее ФиксКолонка.
  4. Создадим вертикальную именованную колонку для динамических данных (которая будет дублироваться по горизонтали для каждого месяца) и назовем ее ДинамическаяКолонка.

В результате на пересечении этих областей мы получаем четыре уникальные зоны, к которым сможем обращаться из кода:

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

Рассмотрим практическую реализацию. Предположим, у нас есть Таблица Значений с именем ТЗ_Данные, содержащая колонки Контрагент, Месяц (тип Дата) и Сумма. Нам необходимо построить отчет, где строки — это контрагенты, а колонки — месяцы, в которых были платежи.

Проанализируем и выполним следующий программный код:


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

// Получаем области пересечения из макета
ОбластьШапкаЛево  = Макет.ПолучитьОбласть("Шапка|ФиксКолонка");
ОбластьШапкаМесяц = Макет.ПолучитьОбласть("Шапка|ДинамическаяКолонка");

ОбластьСтрокаЛево  = Макет.ПолучитьОбласть("Строка|ФиксКолонка");
ОбластьСтрокаМесяц = Макет.ПолучитьОбласть("Строка|ДинамическаяКолонка");

// Сначала определим уникальный список месяцев для формирования колонок
ТаблицаКолонок = ТЗ_Данные.Скопировать();
ТаблицаКолонок.Свернуть("Месяц");
ТаблицаКолонок.Сортировать("Месяц Возр");

// --- ШАГ 1. ВЫВОД ШАПКИ ТАБЛИЦЫ ---
// Выводим крайнюю левую ячейку шапки (начинаем строку)
ТабДок.Вывести(ОбластьШапкаЛево);

// В цикле присоединяем названия месяцев по горизонтали справа
Для Каждого СтрКолонка Из ТаблицаКолонок Цикл
    // Форматируем дату для вывода названия месяца (например, "Январь 2023")
    ОбластьШапкаМесяц.Параметры.ИмяМесяца = Формат(СтрКолонка.Mesyac, "ДФ='MMMM yyyy'");
    ТабДок.Присоединить(ОбластьШапкаМесяц);
КонецЦикла;

// --- ШАГ 2. ВЫВОД СТРОК С ДАННЫМИ ---
// Получаем уникальный список контрагентов для строк
ТаблицаСтрок = ТЗ_Данные.Скопировать();
ТаблицаСтрок.Свернуть("Контрагент");

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

// Отображаем готовый отчет пользователю
ТабДок.Показать();

Важные технические нюансы и оптимизация кода

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

1. Кэширование областей макета. Обратите внимание, что в примере кода получение областей из макета с помощью метода ПолучитьОбласть() выполняется до начала основных циклов. Это критически важно для оптимизации. Обращение к макету — ресурсоемкая операция. Если вы будете вызывать метод ПолучитьОбласть() внутри циклов по строкам и колонкам, производительность отчета при больших объемах данных резко снизится.

2. Независимость параметров при присоединении. Часто у начинающих разработчиков возникает вопрос: "Если мы используем один и тот же объект области ОбластьСтрокаМесяц в цикле и постоянно меняем его параметр Сумма, не затрутся ли значения в уже выведенных колонках?". Нет, не затрутся. В момент вызова метода Присоединить() или Вывести() платформа копирует текущее состояние области макета вместе со всеми заполненными параметрами в итоговый табличный документ. Последующие изменения параметров переменной области никак не влияют на уже сформированные ячейки отчета.

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

ТабДок.ОриентацияСтраницы = ОриентацияСтраницы.Ландшафт;

4. Оформление объединенных ячеек. Будьте осторожны при использовании объединенных ячеек в присоединяемых областях. Если ваша присоединяемая область по вертикали состоит из нескольких объединенных строк, убедитесь, что высота всех строк этой области жестко зафиксирована в макете. В противном случае, при включенном свойстве ячеек "Автовысота", строки таблицы могут некрасиво разъехаться по высоте.

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

← На главную