В практике разработки на платформе 1С:Предприятие часто возникает задача оптимизации пространства печатной формы. Типичный пример: в документе есть две табличные части, например, Работы и Материалы. По умолчанию их выводят друг под другом, но если строк в обеих частях немного, логичнее и компактнее расположить их рядом, в одной строке макета. Это позволяет пользователю сразу видеть взаимосвязь данных или просто экономить бумагу при печати.
Проблема заключается в том, что стандартный метод Вывести() всегда добавляет новую строку в табличный документ вниз, а метод Присоединить() работает в рамках текущей строки, но требует четкой синхронизации. Разберем несколько способов реализации этой задачи: от простого использования временных документов до профессионального метода с единым циклом и запросом.
Рассмотрим вариант, к которому пришел автор темы. Этот способ интуитивно понятен: мы формируем две независимые вертикальные таблицы во временных объектах ТабличныйДокумент, а затем «склеиваем» их в итоговой форме. Проанализируем логику этого решения по шагам.
Сначала мы создаем два буферных документа. В первый мы в цикле выводим все строки из первой табличной части, а во второй — из второй. Важно, чтобы области в макете были подготовлены заранее и разбиты по вертикали (имели именованные колонки).
// Создаем временные контейнеры для каждой части таблицы
ТабДок1 = Новый ТабличныйДокумент();
ТабДок2 = Новый ТабличныйДокумент();
// Получаем области из макета (предположим, в макете области разделены по вертикали)
СтрокиРаботы = Макет.ПолучитьОбласть("Строки|Работы");
СтрокиМатериалы = Макет.ПолучитьОбласть("Строки|Материалы");
// Заполняем первую временную таблицу (Работы)
Для каждого СтрокаРабот Из СсылкаНаОбъект.Работы Цикл
СтрокиРаботы.Параметры.КодРаб = СтрокаРабот.Работа.Артикул;
СтрокиРаботы.Параметры.Работа = СтрокаРабот.Работа.Наименование;
СтрокиРаботы.Параметры.Стоимость = СтрокаРабот.СуммаВсего;
ТабДок1.Вывести(СтрокиРаботы);
КонецЦикла;
// Заполняем вторую временную таблицу (Материалы)
Для каждого СтрокаТовары из СсылкаНаОбъект.Товары цикл
СтрокиМатериалы.Параметры.Товар = СтрокаТовары.Номенклатура.Наименование;
СтрокиМатериалы.Параметры.Кол = СтрокаТовары.Количество;
СтрокиМатериалы.Параметры.Стоимость = СтрокаТовары.СуммаВсего;
ТабДок2.Вывести(СтрокиМатериалы);
КонецЦикла;
// Соединяем все в основной документ
ТабДокумент.Вывести(ТабДок1);
ТабДокумент.Присоединить(ТабДок2);
Преимущества этого метода: простота реализации и отсутствие необходимости синхронизировать количество строк в циклах. Однако стоит помнить, что метод Присоединить() для целого табличного документа работает корректно только в том случае, если высота строк в обоих документах совпадает. Если в одной таблице текст перенесся на вторую строку, а в другой — нет, визуальная сетка таблицы может «поплыть».
Более надежный способ с точки зрения верстки — это использование одного цикла, который проходит по максимальному количеству строк из двух табличных частей. Выясним, как это работает на практике. Мы определяем, в какой таблице больше записей, и итерируемся по этому числу. На каждом шаге мы проверяем, есть ли данные в текущей строке для первой и второй таблицы.
Рассмотрим пример кода для реализации такого подхода:
// Определяем максимальное количество итераций
КолСтрок1 = СсылкаНаОбъект.Работы.Количество();
КолСтрок2 = СсылкаНаОбъект.Товары.Количество();
МаксКоличество = Макс(КолСтрок1, КолСтрок2);
Для Индекс = 0 По МаксКоличество - 1 Цикл
// Работаем с левой частью (Работы)
ОбластьЛево = Макет.ПолучитьОбласть("Строка|Работы");
Если Индекс < КолСтрок1 Тогда
ТекСтрока = СсылкаНаОбъект.Работы[Индекс];
ОбластьЛево.Параметры.Заполнить(ТекСтрока);
Иначе
// Если строк в ТЧ меньше, чем итераций, выводим пустую область для сохранения структуры
ОбластьЛево.Параметры.Работа = "";
КонецЕсли;
ТабДокумент.Вывести(ОбластьЛево);
// Работаем с правой частью (Материалы)
ОбластьПраво = Макет.ПолучитьОбласть("Строка|Материалы");
Если Индекс < КолСтрок2 Тогда
ТекСтрока = СсылкаНаОбъект.Товары[Индекс];
ОбластьПраво.Параметры.Заполнить(ТекСтрока);
Иначе
ОбластьПраво.Параметры.Товар = "";
КонецЕсли;
ТабДокумент.Присоединить(ОбластьПраво);
КонецЦикла;
Этот метод гарантирует, что каждая пара ячеек будет находиться строго в одной строке табличного документа. Даже если одна ТЧ пустая, а вторая заполнена, структура таблицы не нарушится.
Проанализируем ситуацию, когда данных много и обращение к табличным частям в цикле может быть неоптимальным. Профессиональный подход подразумевает подготовку данных в одном запросе. Для этого нам нужно соединить две таблицы по «искусственному» полю — номеру строки.
Разберем алгоритм построения такого запроса:
ТЧ1.НомерСтроки >= ТЧ2.НомерСтроки).ПорядковыйНомер.В результате мы получим плоскую таблицу, где в каждой строке результата запроса будут поля и для работ, и для материалов. После этого вывод в печатную форму превращается в один простой цикл по выборке Пока Выборка.Следующий() Цикл, внутри которого сначала вызывается Вывести() для левой части макета, а затем Присоединить() для правой.
При реализации горизонтального объединения таблиц следует учитывать несколько критически важных моментов, которые часто упускают начинающие разработчики:
АвтоВысотаСтроки, будьте осторожны. Высота всей строки в итоговом документе будет равна высоте самой высокой ячейки. Если в левой части ячейка растянулась из-за длинного текста, правая ячейка в этой же строке также станет выше, что может выглядеть некрасиво, если в ней текста мало.ТабДокумент.ПроверитьВывод(МассивОбластей). В массив нужно передать обе области (левую и правую). Это позволит системе заранее рассчитать, поместится ли эта «двойная» строка на текущую страницу по ширине и высоте.ЗаполнитьЗначенияСвойств(). Лучше использовать префиксы, например, Раб_Наименование и Мат_Наименование.Присоединить() убедитесь, что в макете правая граница левой области и левая граница правой области совпадают или настроены так, чтобы при соединении не получалось двойных линий рамки.Выбор конкретного способа зависит от сложности вашей задачи. Для простых разовых отчетов вполне подойдет метод с временными документами (Способ 1). Если же вы разрабатываете тиражное решение или печатную форму для высоконагруженной системы, лучше использовать синхронный цикл (Способ 2) или подготовку данных запросом (Способ 3).