Разработка печатных форм в 1С:Предприятии — задача привычная, но ровно до тех пор, пока дизайн-макет не потребует от нас многоколоночного вывода (так называемой «газетной» верстки). Типичный пример — печать дипломов, свидетельств, удостоверений или двусторонних буклетов, где лист делится на левую и правую части, заполняемые независимо друг от друга.
При попытке реализовать такую структуру стандартными методами Вывести() и Присоединить() разработчики часто сталкиваются с неприятным поведением платформы: присоединенные области упрямо выводятся в правый нижний угол страницы, высота строк «разъезжается», а сетка колонок деформируется. В этой статье мы подробно разберем, почему это происходит, и рассмотрим несколько надежных способов реализации двухколоночного макета.
Выясним причины некорректного поведения платформы и пошагово разберем рабочие программные решения.
---
Прежде чем перейти к коду, давайте проанализируем физику работы метода Присоединить(). Согласно синтакс-помощнику, этот метод присоединяет табличный документ к результирующему, помещая его в следующей колонке правее самой правой выведенной колонки, начиная со строки, с которой выводился предыдущий табличный документ.
Если мы выводим левую колонку по частям (например, сначала шапку, затем несколько строк таблицы, а потом подвал), платформа фиксирует текущую активную строку вывода все ниже и ниже. Когда мы решим наконец присоединить правую часть, система поместит ее не в самый верх листа, а на уровне последней выведенной строки левой части. В результате мы получаем пустую левую колонку вверху, заполненную левую колонку внизу и примкнувшую к ней справа правую колонку. Документ безнадежно испорчен.
Вторая распространенная ошибка — использование бесконечных областей. Если область макета задана только горизонтальными строками, она по умолчанию имеет бесконечную ширину (все доступные колонки макета). Присоединить что-либо сбоку к «бесконечной» области физически невозможно, поэтому платформа автоматически переносит вывод вниз.
---
Самый простой способ победить эту проблему в рамках стандартного табличного документа — использовать строго ограниченные области (пересечения горизонтальных и вертикальных секций) совместно с временными табличными документами-контейнерами.
Давайте разберем по шагам, как правильно настроить макет и написать код:
Ctrl + Shift + N), например, ЛеваяЧасть и ПраваяЧасть.Колонка.Посмотрим на рабочий пример реализации такой логики:
&НаСервере
Функция ПечатьНаСервере()
Макет = РеквизитФормыВЗначение("Объект").ПолучитьМакет("Макет");
// Получаем области на пересечении горизонтальных строк и вертикальных колонок
ЛеваяОбласть = Макет.ПолучитьОбласть("ЛеваяЧасть|Колонка");
ПраваяОбласть = Макет.ПолучитьОбласть("ПраваяЧасть|Колонка");
// Создаем три табличных документа
ТабДокЛево = Новый ТабличныйДокумент;
ТабДокПраво = Новый ТабличныйДокумент;
ТабДокОбщ = Новый ТабличныйДокумент;
// Заполняем левый табличный документ (он может состоять из множества выводимых областей)
ТабДокЛево.Вывести(ЛеваяОбласть);
ТабДокЛево.Вывести(ЛеваяОбласть); // Симулируем вывод нескольких блоков
// Заполняем правый табличный документ независимо
ТабДокПраво.Вывести(ПраваяОбласть);
ТабДокПраво.Вывести(ПраваяОбласть);
// Собираем их вместе в общий документ
ТабДокОбщ.Вывести(ТабДокЛево);
ТабДокОбщ.Присоединить(ТабДокПраво);
Возврат ТабДокОбщ;
КонецФункции
Важный нюанс: если вы формируете многостраничный документ, где на каждой странице должны быть две свои колонки, правый временный табличный документ необходимо обязательно очищать перед заполнением новой страницы с помощью метода Очистить(), иначе данные начнут дублироваться и накапливаться. Посмотрим на этот сценарий:
// Пример вывода многостраничного двухколоночного документа
ТабДок = Новый ТабличныйДокумент;
ТабДокПраво = Новый ТабличныйДокумент;
// Страница 1
ТабДок.Вывести(ЛеваяЧасть);
ТабДокПраво.Вывести(ПраваяЧасть);
ТабДок.Присоединить(ТабДокПраво);
// Переходим на вторую страницу
ТабДок.ВывестиГоризонтальныйРазделительСтраниц();
// Страница 2
ТабДок.Вывести(ЛеваяЧасть);
ТабДокПраво.Очистить(); // Обязательно очищаем контейнер перед повторным заполнением!
ТабДокПраво.Вывести(ПраваяЧасть);
ТабДок.Присоединить(TabДокПраво);
---
Что делать, если левая и правая стороны документа имеют абсолютно разную высоту строк, сложную структуру и выводятся хаотично? В этом случае метод Присоединить() неизбежно приведет к «разъезжанию» строк по высоте.
Для решения этой проблемы мы можем применить метод ВставитьОбласть(). Он позволяет скопировать заполненный блок ячеек из временного документа и принудительно «вставить» его в строго заданные координаты результирующего документа, не сдвигая при этом уже выведенные элементы.
Рассмотрим пример реализации:
// Сначала полностью формируем левую часть в основном документе
ОбщийТабДок.Вывести(ОбластьЛевойКолонки);
// Запоминаем координату, с которой должна начаться правая колонка (например, первая строка)
НачальнаяСтрокаПравойКолонки = 1;
НомерКолонкиВставки = 6; // Например, правая колонка начнется с 6-го столбца
// Формируем правую колонку во временном документе
ВременныйТабДок = Новый ТабличныйДокумент;
ВременныйТабДок.Вывести(ОбластьПравойКолонки);
// Определяем диапазон-источник во временном документе
ОбластьИсточник = ВременныйТабДок.Область(1, 1, ВременныйТабДок.ВысотаТаблицы, ВременныйТабДок.ШиринаТаблицы);
// Определяем диапазон-приемник в общем документе
ОбластьПриемник = ОбщийТабДок.Область(НачальнаяСтрокаПравойКолонки, НомерКолонкиВставки);
// Вставляем область без смещения существующих ячеек
ОбщийТабДок.ВставитьОбласть(ОбластьИсточник, ОбластьПриемник, ТипСмещенияТабличногоДокумента.БезСмещения);
Использование параметра ТипСмещенияТабличногоДокумента.БезСмещения гарантирует, что вставка правой половины документа поверх пустых ячеек справа никак не повлияет на структуру и высоту строк уже выведенной левой половины.
---
Когда вы объединяете разнородные области или вставляете одну колонку рядом с другой, ширины ячеек могут начать конфликтовать. Сетка левой колонки будет пытаться сжать или растянуть сетку правой колонки.
Чтобы избежать этого, в платформе предусмотрен замечательный метод СоздатьФорматСтрок(). Он изолирует сетку выбранных строк от остальной части документа. Давайте посмотрим, как его применять:
// Выделяем строки, в которых находятся наши колонки
ОбластьСтрок = ОбщийТабДок.Область(1,, ОбщийТабДок.ВысотаТаблицы);
// Изолируем их формат
ОбластьСтрок.СоздатьФорматСтрок();
После вызова этого метода любые изменения ширины колонок внутри выделенного диапазона строк перестанут влиять на ширину колонок в строках выше или ниже этого диапазона.
---
Если вам необходимо напечатать сложный бланк (например, сертифицированное удостоверение), где текст должен располагаться строго в определенных границах, а использование ячеек сводит вас с ума постоянным «съезжанием» границ, обратите внимание на графический режим верстки.
Вместо использования ячеек табличного документа мы можем разместить в макете объекты типа Рисунок с типом Текст.
Программная работа с такими объектами выглядит следующим образом:
ОбластьМакета = Макет.ПолучитьОбласть("ОсновнойЛист");
// Заполняем параметры в текстовых рисунках напрямую
ОбластьМакета.Рисунки.ТекстЛевойКолонки.Текст = "Длинное наименование образовательной программы...";
ОбластьМакета.Рисунки.ТекстПравойКолонки.Текст = "ФИО слушателя и сведения о квалификации...";
ТабДок.Вывести(ОбластьМакета);
Этот метод полностью решает проблему «перетекания» и неконтролируемого сдвига областей, гарантируя идеальную верстку пиксель-в-пиксель.
---
Если требования к оформлению документа слишком высоки (требуются сложные колонтитулы, автоматический перенос длинных названий на вторую страницу с сохранением структуры колонок), классический табличный документ 1С становится слишком тесным инструментом.
Многие разработчики отказываются от Word из-за медленной работы технологии COM-соединения и необходимости устанавливать MS Office на сервере. Однако современная Библиотека стандартных подсистем (БСП) предлагает гораздо более изящное решение: **печать по шаблонам .docx на основе прямого анализа XML**.
Платформа сама распаковывает zip-архив docx-файла на сервере, производит текстовую замену параметров в XML-структуре документа (тэги вида {ИмяПараметра}) и собирает файл обратно. Для этого не требуется установленный Microsoft Office на сервере, а скорость генерации сопоставима с обычным выводом табличного документа.
При этом вы получаете все преимущества профессионального текстового процессора: двухколоночный текст будет идеально перетекать с первой страницы на вторую, а подвал (например, «Город, Год») останется строго на своем месте за счет использования стандартных нижних колонтитулов Word.
---
Мы рассмотрели целый арсенал средств для решения проблемы двухколоночной верстки в 1С. Выбор конкретного инструмента зависит от ваших задач:
ВставитьОбласть() с отключенным смещением (Решение 2).