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