Как скопировать сформированный табличный документ в 1С без потери табличной части?

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

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

Разберем подробнее, почему возникает такое поведение платформы 1С:Предприятие, и рассмотрим надежные способы решения этой задачи.

Выясним причину: почему пропадает табличная часть при использовании «ВставитьОбласть»

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

Когда мы получаем прямоугольную область ячеек с явным указанием номеров колонок:


ВсяОбласть = ТабДокумент.Область(1, 1, ТабДокумент.ВысотаТаблицы, ТабДокумент.ШиринаТаблицы);
ТабДокумент.ВывестиГоризонтальныйРазделительСтраниц();
ТабДокумент.ВставитьОбласть(ВсяОбласть, , ТипСмещенияТабличногоДокумента.ПоВертикали);

происходит следующее:

  1. Платформа 1С пытается сопоставить сетку ячеек источника с сеткой колонок приемника. Если в копируемом диапазоне присутствуют строки с разными форматами, жесткая адресация по колонкам разрушает структуру подчиненных колонок, из-за чего табличная часть визуально пропадает или схлопывается.
  2. Если во втором параметре метода ВставитьОбласть() область-приемник опущена, вставка по умолчанию производится в верхний левый угол (ячейку R1C1), что приводит к сдвигу существующих данных и непредсказуемым наложениям.
  3. Метод ВставитьОбласть() работает исключительно с сеткой ячеек. Если в документе присутствовали графические элементы (логотипы компаний, факсимиле, штрихкоды), они не входят в коллекцию ячеек и при таком копировании не перенесутся.

Решение 1. Формирование через промежуточный табличный документ и метод «Вывести»

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

Посмотрим на алгоритм реализации:

  1. Создаем новый результирующий табличный документ.
  2. Выводим в него исходный сформированный документ.
  3. Вставляем горизонтальный разделитель страниц.
  4. Выводим исходный документ второй раз.

Разберем пример кода на встроенном языке:


// Создаем новый результирующий табличный документ
ИтоговыйТабДок = Новый ТабличныйДокумент;

// Выводим первый экземпляр документа
ИтоговыйТабДок.Вывести(ТабДокумент);

// Добавляем разделитель страниц между копиями
ИтоговыйТабДок.ВывестиГоризонтальныйРазделительСтраниц();

// Выводим второй экземпляр документа
ИтоговыйТабДок.Вывести(ТабДокумент);

// При необходимости переопределяем возвращаемый документ
ТабДокумент = ИтоговыйТабДок;

Решение 2. Клонирование через сериализацию с заменой текста

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

Рассмотрим по шагам данный подход:

  1. Создаем полную копию объекта с помощью ЗначениеИзСтрокиВнутр() и ЗначениеВСтрокуВнутр().
  2. В полученном клоне находим нужный фрагмент текста с помощью функции НайтиТекст() и заменяем его.
  3. Присоединяем измененный клон к исходному документу через метод Вывести().

// Выполняем глубокое клонирование исходного документа
КлонТабДок = ЗначениеИзСтрокиВнутр(ЗначениеВСтрокуВнутр(ТабДокумент));

// Выполняем поиск и замену текста во втором экземпляре
ОбластьСлова = КлонТабДок.НайтиТекст("Счет");
Если ОбластьСлова <> Неопределено Тогда
    ОбластьСлова.Текст = "Акт";
КонецЕсли;

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

Решение 3. Копирование строк целиком без явного указания колонок

Если по условиям задачи требуется остаться в рамках одного табличного документа и использовать метод ВставитьОбласть(), необходимо исключить жесткую привязку к колонкам. Адресация должна производиться строго по номерам строк.

Посмотрим, как задавать области для корректного переноса форматов:


ВысотаИсходная = ТабДокумент.ВысотаТаблицы;

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

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

// Задаем целевую область для вставки (строка сразу за разделителем)
СтрокаВставки = ТабДокумент.ВысотаТаблицы + 1;
ОбластьПриемник = ТабДокумент.Область(СтрокаВставки, , СтрокаВставки, );

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

В этом случае платформа копирует строки вместе с их индивидуальной разметкой, не пытаясь принудительно подогнать колонки под первый формат.

Решение 4. Архитектурная альтернатива — формирование в цикле

На практике наиболее надежным и поддерживаемым способом является отказ от пост-обработки готового табличного документа. Вместо поиска и подмены текста надежнее сразу вызывать процедуру вывода макета в цикле, передавая нужное наименование документа в качестве параметра макета.

Разберем пример структуры процедуры печати:


МассивЗаголовков = Новый Массив;
МассивЗаголовков.Добавить("Счет");
МассивЗаголовков.Добавить("Акт");

Для НомерПрохода = 0 По МассивЗаголовков.ВГраница() Цикл
    Если НомерПрохода > 0 Тогда
        ТабДокумент.ВывестиГоризонтальныйРазделительСтраниц();
    КонецЕсли;
    
    // Передаем заголовок в параметры шапки макета
    ОбластьШапка.Параметры.ЗаголовокДокумента = МассивЗаголовков[НомерПрохода];
    ТабДокумент.Вывести(ОбластьШапка);
    
    // Выводим табличную часть и подвал
    // ...
КонецЦикла;

Такой подход полностью исключает риск искажения форматирования, некорректного переноса графических данных и гарантирует правильное поведение печатной формы независимо от версии платформы 1С:Предприятие.

← На главную