Как вывести данные в табличный документ в две колонки при разном количестве строк в блоках

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

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

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

Метод 1. Синхронный вывод строк (Метод «Максимальной высоты»)

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

Проанализируем алгоритм по шагам:

  1. Определяем пару объектов для вывода (например, «Вася» пойдет слева, а «Петя» — справа).
  2. Получаем данные табличных частей для обоих объектов.
  3. Сравниваем количество строк в левом и правом наборе данных. Нам нужно найти максимальное значение, чтобы цикл отработал до полного завершения самого длинного блока.
  4. В цикле выполняем вывод: сначала используем метод Вывести() для левой части строки, затем Присоединить() для правой.
  5. Важный нюанс: если в одном из блоков строки закончились раньше, чем в другом, мы должны вывести пустую область-заглушку, чтобы сохранить структуру колонок и не нарушить границы следующей пары блоков.

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


// Предположим, ДанныеСлева и ДанныеСправа - это массивы со строками
МаксСтрок = Макс(ДанныеСлева.Количество(), ДанныеСправа.Количество());

// Выводим шапки блоков
ОбластьШапкаЛ = Макет.ПолучитьОбласть("Шапка");
ОбластьШапкаП = Макет.ПолучитьОбласть("Шапка");
ОбластьШапкаЛ.Параметры.Имя = "Вася";
ОбластьШапкаП.Параметры.Имя = "Петя";

ТабДок.Вывести(ОбластьШапкаЛ);
ТабДок.Присоединить(ОбластьШапкаП);

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

Этот метод гарантирует, что следующая пара блоков (например, «Маша» и «Коля») начнется строго под самым длинным предыдущим блоком, так как высота левой и правой части была программно выровнена.

Метод 2. Подготовка данных в запросе (Четные и нечетные группы)

Если структура данных позволяет, мы можем переложить логику разделения на колонки на плечи SQL-движка 1С. Разберем ситуацию, когда нам нужно вывести список записей в два столбца. Мы можем пронумеровать записи в запросе, разделить их на «четные» и «нечетные» и соединить их горизонтально.

Для этого в языке запросов 1С v8.3 удобно использовать функцию АВТОНОМЕРЗАПИСИ(). Рассмотрим пример логики запроса:


// 1. Получаем все данные с порядковым номером
ВЫБРАТЬ
    ТЧ.Номенклатура,
    АВТОНОМЕРЗАПИСИ() КАК ПорядковыйНомер
ПОМЕСТИТЬ ВТ_ВсеДанные
ИЗ
    Документ.Реализация.Товары КАК ТЧ;

// 2. Выбираем нечетные (левая колонка)
ВЫБРАТЬ
    ВТ.Номенклатура КАК ИмяЛево,
    (ВТ.ПорядковыйНомер + 1) / 2 КАК Группа
ПОМЕСТИТЬ ВТ_Лево
ИЗ
    ВТ_ВсеДанные КАК ВТ
ГДЕ
    ВТ.ПорядковыйНомер % 2 <> 0;

// 3. Выбираем четные (правая колонка)
ВЫБРАТЬ
    ВТ.Номенклатура КАК ИмяПраво,
    ВТ.ПорядковыйНомер / 2 КАК Группа
ПОМЕСТИТЬ ВТ_Право
ИЗ
    ВТ_ВсеДанные КАК ВТ
ГДЕ
    ВТ.ПорядковыйНомер % 2 = 0;

// 4. Соединяем по виртуальному номеру группы
ВЫБРАТЬ
    Л.ИмяЛево,
    П.ИмяПраво
ИЗ
    ВТ_Лево КАК Л
ПОЛНОЕ СОЕДИНЕНИЕ ВТ_Право КАК П ПО Л.Группа = П.Группа;

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

Метод 3. Использование временных табличных документов

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

  1. Создаем два вспомогательных объекта ТабличныйДокумент (назовем их БуферЛево и БуферПраво).
  2. Заполняем БуферЛево всеми данными, которые должны идти в первую колонку (с заголовками, строками и итогами).
  3. Аналогично заполняем БуферПраво.
  4. Затем в основном цикле переносим данные из буферов в основной документ.

Для переноса удобно использовать метод ВставитьОбласть(). Проанализируем пример кода для объединения:


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

    Если НомерСтроки <= БуферПраво.ВысотаТаблицы Тогда
        // Присоединяем область из правой колонки буфера
        ОбластьИзБуфера = БуферПраво.Область(НомерСтроки, 1, НомерСтроки, БуферПраво.ШиринаТаблицы);
        ТабДок.Присоединить(ОбластьИзБуфера);
    КонецЕсли;
    
КонецЦикла;

Преимущество данного метода заключается в том, что 1С корректно переносит форматирование, ширину колонок и объединение ячеек из буферных документов. Это позволяет верстать левую и правую части независимо друг от друга.

Советы по оформлению макета

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

Рассмотренные подходы позволяют гибко управлять выводом в ТабличныйДокумент, избегая наложения областей и обеспечивая ровное расположение блоков «шахматкой» или параллельными колонками вне зависимости от объема данных в каждой из них.

← На главную