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

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

Разработчики 1С часто сталкиваются с задачей объединения нескольких различных отчетов или печатных форм в один документ для вывода на печать. Основная сложность заключается в том, что разные печатные формы (например, Счет на оплату, Товарная накладная Торг-12 и Счет-фактура) имеют абсолютно разную структуру, ширину и количество колонок. Если попытаться вывести их друг за другом в один табличный документ обычным методом Вывести(), колонки последующих документов автоматически подстроятся под ширину колонок первого выведенного документа. В результате верстка «съезжает», таблицы деформируются, и документ становится нечитаемым.

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

Почему возникает проблема смещения колонок?

По умолчанию объект ТабличныйДокумент в платформе 1С:Предприятие имеет единую жесткую сетку колонок на весь лист. Любое изменение ширины колонки в одной строке неизбежно влияет на ширину этой же колонки во всех остальных строках документа. Чтобы обойти это ограничение, в платформе существует специальный механизм — индивидуальный формат строк. Он позволяет разорвать связь между сетками колонок для разных строк или целых диапазонов строк табличного документа.

Способ №1: Интерактивное создание индивидуального формата строк в макете

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

  1. Откройте макет первой (базовой) печатной формы в конфигураторе.
  2. Перейдите в самый низ макета и выделите строки в количестве, необходимом для размещения второй печатной формы.
  3. Попытайтесь изменить ширину любой колонки внутри выделенной области.
  4. Платформа выведет системное предупреждение: «Для выделенных строк будет создан новый формат строк». Согласитесь с этим действием.
  5. После этого выделенные строки получат собственную независимую разметку колонок. Теперь вы можете скопировать данные из второго макета, вставить их в эту область и детально настроить ширину колонок под его требования.

Главный минус этого подхода: если в будущем изменится один из базовых макетов, вам придется вручную переделывать всю объединенную форму. Это создает огромные трудозатраты при поддержке системы.

Способ №2: Универсальное программное объединение табличных документов

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

Ниже представлен готовый программный код процедуры, которая принимает документ-приемник и вставляемый документ, анализирует структуру колонок вставляемого файла, создает новые форматы строк и корректно переносит данные ячеек:


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

Функция ПолучитьЗначениеШириныСтрокой(пМассив, разделитель = ";")
    рез = "";
    Для Каждого стр Из пМассив Цикл 
        рез = рез + стр + разделитель;
    КонецЦикла;
    Возврат рез;    
КонецФункции

Анализ работы программного алгоритма

Давайте подробно разберем ключевые шаги этого алгоритма, чтобы понимать физику процесса:

  1. Копирование во временный буфер: Метод ПолучитьОбласть() позволяет сделать полную копию макета. Это критически важно, так как дальнейшие манипуляции не должны испортить оригинальный табличный документ.
  2. Разъединение объединенных ячеек: Метод Разъединить() убирает все объединения ячеек во временном документе. Если этого не сделать, то при обращении к ширине конкретной колонки платформа вернет некорректные или пустые значения из-за влияния объединенных областей.
  3. Анализ и группировка форматов строк: Алгоритм построчно сканирует ширину каждой ячейки и собирает строки с одинаковым набором ширин в группы. Это минимизирует количество вызовов ресурсоемких функций платформы.
  4. Использование метода СоздатьФорматСтрок(): Это 핵심-метод решения. При вставке области в целевой документ мы принудительно вызываем метод СоздатьФорматСтрок() для вставляемого диапазона, указывая платформе на то, что эти строки имеют свою уникальную геометрию колонок.
  5. Применение точной ширины: В цикле по всем колонкам вставленного диапазона мы явно присваиваем каждому столбцу ширину, полученную на этапе анализа.

Способ №3: Использование «миллиметровки» (модульной сетки)

Другой профессиональный подход, часто применяемый при разработке сложных комплексных отчетов, — это верстка макетов по методу «миллиметровки».

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

Преимущества метода миллиметровки:

Минусы: Метод требует колоссальной аккуратности от разработчика на этапе создания макета и усложняет дальнейшее редактирование шаблонов печатных форм.

Способ №4: Использование коллекции печатных форм в БСП

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

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

Ограничения и важные технические нюансы

Перед тем как внедрять программное объединение печатных форм, обязательно проанализируйте следующие факторы:

← На главную