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