Как вывести табличный документ в две колонки в 1С:Предприятие?

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

Разработка печатных форм в 1С:Предприятии — задача привычная, но ровно до тех пор, пока дизайн-макет не потребует от нас многоколоночного вывода (так называемой «газетной» верстки). Типичный пример — печать дипломов, свидетельств, удостоверений или двусторонних буклетов, где лист делится на левую и правую части, заполняемые независимо друг от друга.

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

Выясним причины некорректного поведения платформы и пошагово разберем рабочие программные решения.

---

Почему метод Присоединить() смещает области вниз?

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

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

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

---

Решение 1: Пересечение секций и промежуточные табличные документы

Самый простой способ победить эту проблему в рамках стандартного табличного документа — использовать строго ограниченные области (пересечения горизонтальных и вертикальных секций) совместно с временными табличными документами-контейнерами.

Давайте разберем по шагам, как правильно настроить макет и написать код:

  1. В макете печатной формы создайте горизонтальные именованные секции (выделив строки и нажав Ctrl + Shift + N), например, ЛеваяЧасть и ПраваяЧасть.
  2. Создайте вертикальные секции (выделив колонки), назвав их, к примеру, Колонка.
  3. В коде обращайтесь к областям через оператор пересечения «|» (вертикальная черта). Это позволит получить четко ограниченный прямоугольник, а не бесконечную строку.
  4. Для сборки страницы используйте схему с тремя табличными документами: один общий (итоговый) и два временных (для левой и правой колонок).

Посмотрим на рабочий пример реализации такой логики:


&НаСервере
Функция ПечатьНаСервере()
    
    Макет = РеквизитФормыВЗначение("Объект").ПолучитьМакет("Макет");
    
    // Получаем области на пересечении горизонтальных строк и вертикальных колонок
    ЛеваяОбласть  = Макет.ПолучитьОбласть("ЛеваяЧасть|Колонка");
    ПраваяОбласть = Макет.ПолучитьОбласть("ПраваяЧасть|Колонка");
    
    // Создаем три табличных документа
    ТабДокЛево  = Новый ТабличныйДокумент;
    ТабДокПраво = Новый ТабличныйДокумент;
    ТабДокОбщ   = Новый ТабличныйДокумент;
    
    // Заполняем левый табличный документ (он может состоять из множества выводимых областей)
    ТабДокЛево.Вывести(ЛеваяОбласть);
    ТабДокЛево.Вывести(ЛеваяОбласть); // Симулируем вывод нескольких блоков
    
    // Заполняем правый табличный документ независимо
    ТабДокПраво.Вывести(ПраваяОбласть);
    ТабДокПраво.Вывести(ПраваяОбласть);
    
    // Собираем их вместе в общий документ
    ТабДокОбщ.Вывести(ТабДокЛево);
    ТабДокОбщ.Присоединить(ТабДокПраво);
    
    Возврат ТабДокОбщ;
    
КонецФункции

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


// Пример вывода многостраничного двухколоночного документа
ТабДок = Новый ТабличныйДокумент;
ТабДокПраво = Новый ТабличныйДокумент;

// Страница 1
ТабДок.Вывести(ЛеваяЧасть);
ТабДокПраво.Вывести(ПраваяЧасть);
ТабДок.Присоединить(ТабДокПраво);

// Переходим на вторую страницу
ТабДок.ВывестиГоризонтальныйРазделительСтраниц();

// Страница 2
ТабДок.Вывести(ЛеваяЧасть);
ТабДокПраво.Очистить(); // Обязательно очищаем контейнер перед повторным заполнением!
ТабДокПраво.Вывести(ПраваяЧасть);
ТабДок.Присоединить(TabДокПраво);

---

Решение 2: Использование метода ВставитьОбласть() для абсолютного позиционирования

Что делать, если левая и правая стороны документа имеют абсолютно разную высоту строк, сложную структуру и выводятся хаотично? В этом случае метод Присоединить() неизбежно приведет к «разъезжанию» строк по высоте.

Для решения этой проблемы мы можем применить метод ВставитьОбласть(). Он позволяет скопировать заполненный блок ячеек из временного документа и принудительно «вставить» его в строго заданные координаты результирующего документа, не сдвигая при этом уже выведенные элементы.

Рассмотрим пример реализации:


// Сначала полностью формируем левую часть в основном документе
ОбщийТабДок.Вывести(ОбластьЛевойКолонки); 

// Запоминаем координату, с которой должна начаться правая колонка (например, первая строка)
НачальнаяСтрокаПравойКолонки = 1;
НомерКолонкиВставки = 6; // Например, правая колонка начнется с 6-го столбца

// Формируем правую колонку во временном документе
ВременныйТабДок = Новый ТабличныйДокумент;
ВременныйТабДок.Вывести(ОбластьПравойКолонки);

// Определяем диапазон-источник во временном документе
ОбластьИсточник = ВременныйТабДок.Область(1, 1, ВременныйТабДок.ВысотаТаблицы, ВременныйТабДок.ШиринаТаблицы);

// Определяем диапазон-приемник в общем документе
ОбластьПриемник = ОбщийТабДок.Область(НачальнаяСтрокаПравойКолонки, НомерКолонкиВставки);

// Вставляем область без смещения существующих ячеек
ОбщийТабДок.ВставитьОбласть(ОбластьИсточник, ОбластьПриемник, ТипСмещенияТабличногоДокумента.БезСмещения);

Использование параметра ТипСмещенияТабличногоДокумента.БезСмещения гарантирует, что вставка правой половины документа поверх пустых ячеек справа никак не повлияет на структуру и высоту строк уже выведенной левой половины.

---

Решение 3: Разделение форматов строк через СоздатьФорматСтрок()

Когда вы объединяете разнородные области или вставляете одну колонку рядом с другой, ширины ячеек могут начать конфликтовать. Сетка левой колонки будет пытаться сжать или растянуть сетку правой колонки.

Чтобы избежать этого, в платформе предусмотрен замечательный метод СоздатьФорматСтрок(). Он изолирует сетку выбранных строк от остальной части документа. Давайте посмотрим, как его применять:


// Выделяем строки, в которых находятся наши колонки
ОбластьСтрок = ОбщийТабДок.Область(1,, ОбщийТабДок.ВысотаТаблицы);

// Изолируем их формат
ОбластьСтрок.СоздатьФорматСтрок();

После вызова этого метода любые изменения ширины колонок внутри выделенного диапазона строк перестанут влиять на ширину колонок в строках выше или ниже этого диапазона.

---

Решение 4: Использование графических объектов (Рисунков)

Если вам необходимо напечатать сложный бланк (например, сертифицированное удостоверение), где текст должен располагаться строго в определенных границах, а использование ячеек сводит вас с ума постоянным «съезжанием» границ, обратите внимание на графический режим верстки.

Вместо использования ячеек табличного документа мы можем разместить в макете объекты типа Рисунок с типом Текст.

Программная работа с такими объектами выглядит следующим образом:


ОбластьМакета = Макет.ПолучитьОбласть("ОсновнойЛист");

// Заполняем параметры в текстовых рисунках напрямую
ОбластьМакета.Рисунки.ТекстЛевойКолонки.Текст = "Длинное наименование образовательной программы...";
ОбластьМакета.Рисунки.ТекстПравойКолонки.Текст = "ФИО слушателя и сведения о квалификации...";

ТабДок.Вывести(ОбластьМакета);

Этот метод полностью решает проблему «перетекания» и неконтролируемого сдвига областей, гарантируя идеальную верстку пиксель-в-пиксель.

---

Решение 5: Шаблоны Word (.docx) через БСП без использования COM-объектов

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

Многие разработчики отказываются от Word из-за медленной работы технологии COM-соединения и необходимости устанавливать MS Office на сервере. Однако современная Библиотека стандартных подсистем (БСП) предлагает гораздо более изящное решение: **печать по шаблонам .docx на основе прямого анализа XML**.

Платформа сама распаковывает zip-архив docx-файла на сервере, производит текстовую замену параметров в XML-структуре документа (тэги вида {ИмяПараметра}) и собирает файл обратно. Для этого не требуется установленный Microsoft Office на сервере, а скорость генерации сопоставима с обычным выводом табличного документа.

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

---

Подведем итоги

Мы рассмотрели целый арсенал средств для решения проблемы двухколоночной верстки в 1С. Выбор конкретного инструмента зависит от ваших задач:

  1. Для простых двухколоночных документов с одинаковой структурой строк идеально подойдет схема с **пересечением областей** и **временными табличными документами** (Решение 1).
  2. Для сложной, асинхронной верстки, где левая и правая стороны формируются независимо, незаменимым инструментом станет метод ВставитьОбласть() с отключенным смещением (Решение 2).
  3. При создании строгих бланков документов (дипломы, сертификаты) лучшим выбором будет использование **рисунков-текстовых полей** (Решение 4).
  4. Если же верстка выходит за рамки возможностей табличного документа 1С — смело используйте серверную генерацию документов **Word через БСП** (Решение 5).
← На главную