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