Как вывести две табличные части документа в одну таблицу печатной формы рядом друг с другом

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

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

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

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

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

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


// Создаем временные контейнеры для каждой части таблицы
ТабДок1 = Новый ТабличныйДокумент();
ТабДок2 = Новый ТабличныйДокумент();

// Получаем области из макета (предположим, в макете области разделены по вертикали)
СтрокиРаботы = Макет.ПолучитьОбласть("Строки|Работы"); 
СтрокиМатериалы = Макет.ПолучитьОбласть("Строки|Материалы"); 

// Заполняем первую временную таблицу (Работы)
Для каждого СтрокаРабот Из СсылкаНаОбъект.Работы Цикл
    СтрокиРаботы.Параметры.КодРаб = СтрокаРабот.Работа.Артикул;
    СтрокиРаботы.Параметры.Работа = СтрокаРабот.Работа.Наименование;
    СтрокиРаботы.Параметры.Стоимость = СтрокаРабот.СуммаВсего;
    ТабДок1.Вывести(СтрокиРаботы);
КонецЦикла;

// Заполняем вторую временную таблицу (Материалы)
Для каждого СтрокаТовары из СсылкаНаОбъект.Товары цикл   
    СтрокиМатериалы.Параметры.Товар = СтрокаТовары.Номенклатура.Наименование;
    СтрокиМатериалы.Параметры.Кол = СтрокаТовары.Количество;
    СтрокиМатериалы.Параметры.Стоимость = СтрокаТовары.СуммаВсего;
    ТабДок2.Вывести(СтрокиМатериалы);
КонецЦикла;

// Соединяем все в основной документ
ТабДокумент.Вывести(ТабДок1);
ТабДокумент.Присоединить(ТабДок2);

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

Способ 2. Синхронный вывод в одном цикле (по индексу)

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

Рассмотрим пример кода для реализации такого подхода:


// Определяем максимальное количество итераций
КолСтрок1 = СсылкаНаОбъект.Работы.Количество();
КолСтрок2 = СсылкаНаОбъект.Товары.Количество();
МаксКоличество = Макс(КолСтрок1, КолСтрок2);

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

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

Способ 3. Формирование данных с помощью запроса

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

Разберем алгоритм построения такого запроса:

  1. Выбираем данные из первой ТЧ и добавляем в нее порядковый номер строки (в 1С это можно сделать через соединение таблицы самой с собой по условию ТЧ1.НомерСтроки >= ТЧ2.НомерСтроки).
  2. Аналогично выбираем данные из второй ТЧ с порядковым номером.
  3. Применяем Полное соединение этих двух выборок по полю ПорядковыйНомер.

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

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

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

  1. Автовысота строк: Если вы используете свойство АвтоВысотаСтроки, будьте осторожны. Высота всей строки в итоговом документе будет равна высоте самой высокой ячейки. Если в левой части ячейка растянулась из-за длинного текста, правая ячейка в этой же строке также станет выше, что может выглядеть некрасиво, если в ней текста мало.
  2. Проверка вывода: Перед тем как выводить и присоединять области, рекомендуется использовать метод ТабДокумент.ПроверитьВывод(МассивОбластей). В массив нужно передать обе области (левую и правую). Это позволит системе заранее рассчитать, поместится ли эта «двойная» строка на текущую страницу по ширине и высоте.
  3. Имена параметров: Следите за тем, чтобы имена параметров в разных областях макета не пересекались, если вы планируете заполнять их через ЗаполнитьЗначенияСвойств(). Лучше использовать префиксы, например, Раб_Наименование и Мат_Наименование.
  4. Границы таблиц: При использовании Присоединить() убедитесь, что в макете правая граница левой области и левая граница правой области совпадают или настроены так, чтобы при соединении не получалось двойных линий рамки.

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

← На главную