Как программно сформировать ТабличныйДокумент с динамическим количеством строк и колонок?

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

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

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

Метод вложенных циклов: Основная концепция

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

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

  1. Создаем внешний цикл, который будет перебирать строки (например, сотрудников).
  2. Внутри этого цикла получаем область макета, отвечающую за левую фиксированную часть (ФИО сотрудника, номер по порядку).
  3. Заполняем параметры этой области и выводим её в результирующий документ методом Вывести().
  4. Запускаем внутренний цикл, который будет перебирать колонки (например, дни месяца).
  5. Внутри внутреннего цикла получаем область макета для ячейки дня, заполняем её параметры (часы, явки) и добавляем её к текущей строке методом Присоединить().

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


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

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

Для Каждого ТекущийСотрудник Из СписокСотрудников Цикл
    
    // Заполняем ФИО в левой части строки
    ОбластьСтрокаЛево.Параметры.Сотрудник = ТекущийСотрудник;
    ТабДок.Вывести(ОбластьСтрокаЛево);
    
    // Теперь добавляем колонки дней справа
    Для День = 1 По КоличествоДнейВПериоде Цикл
        
        // Заполняем данные конкретного дня
        ОбластьКолонкаДень.Параметры.ЗначениеЯчейки = ПолучитьДанныеЗаДень(ТекущийСотрудник, День);
        
        // Присоединяем область к текущей строке справа
        ТабДок.Присоединить(ОбластьКолонкаДень);
        
    КонецЦикла;

КонецЦикла;

Метод «Креста» или работа с пересечениями областей

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

В макете мы определяем горизонтальные секции (например, Строка) и вертикальные (например, День). Чтобы получить область на их пересечении, мы используем оператор вертикальной черты |.

Проанализируем преимущества этого подхода:

  1. Точечная адресация: Мы обращаемся к конкретной ячейке Макет.ПолучитьОбласть("Строка|День").
  2. Сохранение оформления: Если в макете на пересечении заданы особые границы или шрифты, они перенесутся корректно.
  3. Работа с параметрами: Вы гарантированно заполняете параметр именно в той ячейке, которую сейчас выводите.

Прямая адресация через метод Область()

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

Для этого используется метод Область(НомерСтроки, НомерКолонки). Обратите внимание, что нумерация начинается с 1.


// Пример прямой записи в ячейку
НомерСтроки = ТабДок.ВысотаТаблицы; // Текущая последняя строка
НомерКолонки = 5; // Например, колонка для 5-го числа

Ячейка = ТабДок.Область(НомерСтроки, НомерКолонки);
Ячейка.Текст = "8"; // Ставим 8 часов
Ячейка.ЦветФона = WebЦвета.СветлоЗеленый;

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

Оптимизация производительности при больших объемах данных

Если в вашем табеле 500 сотрудников и 31 день, это дает более 15 000 ячеек. При неправильном подходе формирование отчета может занять минуты. Разберем, как ускорить этот процесс:

Управление оформлением и фиксация шапки

Чтобы табель был удобен для пользователя, необходимо предусмотреть фиксацию колонок и заголовков. Представьте, что пользователь прокручивает табель вправо к 31 числу — он должен продолжать видеть ФИО сотрудника.

Используйте следующие свойства объекта ТабличныйДокумент:

  1. ТабДок.ФиксацияСлева = 2; — это зафиксирует первые две колонки (например, Номер и ФИО).
  2. ТабДок.ФиксацияСверху = 3; — зафиксирует шапку с датами.

Также не забывайте про Условное оформление. При выводе колонки дня проверьте, не является ли этот день выходным:


Если ЭтоВыходнойДень(ТекущаяДата) Тогда
    ОбластьДня.ЦветФона = WebЦвета.Лосось;
Иначе
    ОбластьДня.ЦветФона = WebЦвета.Белый;
КонецЕсли;

Решение проблемы «потери» параметров

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

Правильный алгоритм всегда такой: Получили область в переменную -> Заполнили параметры в переменной -> Вывели/Присоединили переменную в документ.

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

← На главную