В данной статье будет приведен пример рекурсивной функции, при помощи которой в табличный документ можно выводить верхний или нижний колонтитулы с произвольным содержимым, а также делать повтор шапки произвольной таблицы в документе (или таблиц, если в документе их несколько).
Сразу уточню, что функция не тестировалась на очень объемных документах, поэтому, если кто-то проведет такое испытание, пожалуйста, напишите результаты в комментариях.
Задача состояла в следующем:
1) выводить не очень большой табличный документ (до 30 листов) с несколькими таблицами,
2) на каждой странице в колонтитуле добавлять нумерацию (если страниц больше одной) и картинку (QR-код) (в том числе корректно выводить нижний колонтитул на последней странице),
3) если какие-либо из таблиц переносились на следующую страницу, необходимо было производить повтор шапки переносимой таблицы, при этом не допустить, чтобы на предыдущей странице осталась только шапка без хотя бы одной строки данных в ней,
4) предусмотреть возможность вывода произвольного верхнего колонтитула (изначально макетом заложен не был).
В частности, это была печатная форма электронной зачетной книжки студента с разбивкой по курсам и семестрам.
Статей на данную тему с примерами вывода колонтитулов и повторов шапки таблицы в интернете, в том числе и здесь на Инфостарте довольно много. Однако, когда возникла описанная выше задача, готового варианта реализации всех названных условий не нашлось (лишь фрагментарно), поэтому был написан некий свой универсальный вариант.
Основным источником идеи для алгоритма был этот пост на Инфостарте от Игоря (за что ему большое спасибо!) под названием "Что делать если в табличный документ нужно выводить колонтитулы с картинками".
Привожу код получившейся основной рекурсивной функции вывода в табличный документ колонтитулов и повторения шапки таблицы:
// Функция вывода в табличный документ колонтитулов и повторения шапки таблицы.
//
// Параметры:
// ТабДок - ТабличныйДокумент - Итоговый табличный документ (размеры должны быть заданы заранее).
// ВыводимаяОбласть - ОбластьТабличногоДокумента - Текущая выводимая область.
// ОбластьПустойСтроки - ОбластьТабличногоДокумента - Область с пустой строкой.
// ОбластьВерхнегоКолонтитула - ОбластьТабличногоДокумента - Необязательный,
// область с верхним колонтитулом.
// ОбластьНижнегоКолонтитула - ОбластьТабличногоДокумента - Необязательный,
// область с нижним колонтитулом.
// ОбластьШапкаТаблицы - ОбластьТабличногоДокумента - Необязательный,
// область шапки текущей выводимой таблицы.
// НомерСтраницы - Число - Необязательный, номер страницы
// (по умолчанию добавляется на нижний колонтитул).
//
// Возвращаемое значение:
// Число - текущий номер страницы.
//
Функция ВыводВТабДокСКолонтитулами(ТабДок,
ВыводимаяОбласть,
ОбластьПустойСтроки,
ОбластьВерхнегоКолонтитула = Неопределено,
ОбластьНижнегоКолонтитула = Неопределено,
ОбластьШапкаТаблицы = Неопределено,
НомерСтраницы = 0)
// Фиксированно заданный параметр: не выводить шапку таблицы,
// если при добавлении к ней пустой строки происходит перенос на след. страницу
ЗапретВисячихШапокТаблицы = Истина;
// Проверка наличия областей.
ЕстьВыводимаяОбласть = ?(ВыводимаяОбласть = Неопределено, Ложь, Истина);
ЕстьВерхнийКолонтитул = ?(ОбластьВерхнегоКолонтитула = Неопределено, Ложь, Истина);
ЕстьНижнийКолонтитул = ?(ОбластьНижнегоКолонтитула = Неопределено, Ложь, Истина);
ЕстьШапкаТаблицы = ?(ОбластьШапкаТаблицы = Неопределено, Ложь, Истина);
// Проверка, является ли эта итерация функции выводом шапки таблицы.
ЭтоВыводШапкиТаблицы = (ЕстьШапкаТаблицы И ВыводимаяОбласть = ОбластьШапкаТаблицы);
// Формирование области с нижним колонтитулом.
ОбластьСНижнимКолонтитулом = Новый Массив;
ОбластьСНижнимКолонтитулом.Добавить(?(ЕстьВыводимаяОбласть, ВыводимаяОбласть, ОбластьПустойСтроки));
// Если параметр задан, то добавляем к шапке пустую строку для дальнейшей проверки.
Если ЗапретВисячихШапокТаблицы Тогда
Если ЭтоВыводШапкиТаблицы Тогда
ОбластьСНижнимКолонтитулом.Добавить(ОбластьПустойСтроки);
КонецЕсли;
КонецЕсли;
// Добавлем непосредственно сам нижний колонтитул в формируемую область нижнего колонтитула.
Если ЕстьНижнийКолонтитул Тогда
ОбластьСНижнимКолонтитулом.Добавить(ОбластьНижнегоКолонтитула);
КонецЕсли;
Если ВыводимаяОбласть = Неопределено И ЕстьНижнийКолонтитул Тогда
// если не задана область вывода, то считаем,
// что нужно сделать завершение текущей страницы (вставить только нижний колонтитул)
// В цикле дополняем текущую страницу пустыми строками до области нижнего колонтитула.
Пока ТабДок.ПроверитьВывод(ОбластьСНижнимКолонтитулом) Цикл
ТабДок.Вывести(ОбластьПустойСтроки);
КонецЦикла;
// Добавляем номер страницы в нижний колонтитул, если их более одной.
Если НомерСтраницы > 1 Тогда
ОбластьНижнегоКолонтитула.Параметры.НомерСтраницы = НомерСтраницы;
КонецЕсли;
ТабДок.Вывести(ОбластьНижнегоКолонтитула);
Иначе
// Проверка - помещается ли выводимая секция на текущую страницу или нужно перейти на новую.
Если Не ТабДок.ПроверитьВывод(ОбластьСНижнимКолонтитулом) Тогда
Если ВыводимаяОбласть = ОбластьПустойСтроки Тогда
Возврат НомерСтраницы;
КонецЕсли;
// Проверка, осталось ли место для пустой строки (если да, то добавляется до колонтитула).
НомерСтраницы = ВыводВТабДокСКолонтитулами(ТабДок,
ОбластьПустойСтроки,
ОбластьПустойСтроки,
ОбластьВерхнегоКолонтитула,
ОбластьНижнегоКолонтитула,
ОбластьШапкаТаблицы,
НомерСтраницы);
// Вывод нижнего колонтитула.
Если ЕстьНижнийКолонтитул Тогда
Если НомерСтраницы > 0 Тогда
ОбластьНижнегоКолонтитула.Параметры.НомерСтраницы = НомерСтраницы;
НомерСтраницы = НомерСтраницы + 1;
КонецЕсли;
ТабДок.Вывести(ОбластьНижнегоКолонтитула);
КонецЕсли;
ТабДок.ВывестиГоризонтальныйРазделительСтраниц();
// Вывод верхнего колонтитула.
Если ЕстьВерхнийКолонтитул Тогда
ТабДок.Вывести(ОбластьВерхнегоКолонтитула);
КонецЕсли;
// Повтор шапки таблицы на новой странице.
Если ЕстьШапкаТаблицы и Не ЭтоВыводШапкиТаблицы Тогда
ТабДок.Вывести(ОбластьШапкаТаблицы);
КонецЕсли;
КонецЕсли;
// Вывод основных данных в документ.
ТабДок.Вывести(ВыводимаяОбласть);
Если ВыводимаяОбласть = ОбластьПустойСтроки Тогда
// Продолжение вывода пустых строк до окончания страницы.
НомерСтраницы = ВыводВТабДокСКолонтитулами(ТабДок,
ОбластьПустойСтроки,
ОбластьПустойСтроки,
ОбластьВерхнегоКолонтитула,
ОбластьНижнегоКолонтитула,
ОбластьШапкаТаблицы,
НомерСтраницы);
КонецЕсли;
КонецЕсли;
Возврат НомерСтраницы;
КонецФункции
Как использовать данную функцию
Что понадобится задать в макете для использования функции:
1) область пустой строки,
2) область верхнего колонтитула с произвольным содержимым,
3) область нижнего колонтитула с произвольным содержимым,
4) области шапок таблиц.
Пример:
В коде их соответственно зачитываем:
ОбластьВерхнегоКолонтитула = Макет.ПолучитьОбласть("ВерхнийКолонтитул");
ОбластьНижнегоКолонтитула = Макет.ПолучитьОбласть("НижнийКолонтитул");
ОбластьПустойСтроки = Макет.ПолучитьОбласть("ПустаяСтрока");
Заполняем колонтитулы значениями параметров, если они присутствуют, например:
// картинка кода (здесь исключительно для примера).
ОбластьНижнегоКолонтитула.Параметры.QRCode = QRCode;
При создании табличного документа необходимо задать размер и параметры страницы, чтобы корректно вычислялись страницы при переносе:
ТабДок = Новый ТабличныйДокумент;
// размер и параметры страницы (необходимо для вычислений страниц)
ТабДок.РазмерСтраницы = "A4";
ТабДок.ОриентацияСтраницы = ОриентацияСтраницы.Ландшафт;
ТабДок.МасштабПечати = 100; // 100%
ТабДок.ПолеСверху = 10;
ТабДок.ПолеСнизу = 5;
ТабДок.ПолеСлева = 15;
ТабДок.ПолеСправа = 10;
НомерСтраницы = 1;
Теперь можно формировать табличный документ, обращаясь к функции при построчном выводе данных в ТабДок.
Пример вывода какой-либо области:
Область = Макет.ПолучитьОбласть("ШапкаДокумента");
// заполняем значениями параметров, если есть.
Область.Параметры.Заполнить(ПараметрыОтчетаВВидеСтруктуры);
НомерСтраницы = ВыводВТабДокСКолонтитулами(ТабДок, Область,
ОбластьПустойСтроки, ОбластьВерхнегоКолонтитула, ОбластьНижнегоКолонтитула,, НомерСтраницы);
Пример вывода таблицы:
ОбластьШапкаТаблицы = Макет.ПолучитьОбласть(ИмяТаблицы + "ШапкаТаблицы");
// Вывод шапки таблицы (с проверкой ЗапретВисячихШапокТаблицы)
НомерСтраницы = ВыводВТабДокСКолонтитулами(ТабДок, ОбластьШапкаТаблицы,
ОбластьПустойСтроки, ОбластьВерхнегоКолонтитула,
ОбластьНижнегоКолонтитула, ОбластьШапкаТаблицы, НомерСтраницы);
// Построчный вывод строк таблицы с данными.
Для каждого Строка из ВыводимаяТаблица Цикл
Область = Макет.ПолучитьОбласть(ИмяТаблицы + "Данные");
Область.Параметры.Заполнить(ПараметрыОтчетаВВидеСтруктуры); // заполняем значениями параметров.
// Вывод очередной строки таблицы с проверкой переноса и повтором шапки таблицы.
НомерСтраницы = ВыводВТабДокСКолонтитулами(ТабДок, Область, ОбластьПустойСтроки, О
бластьВерхнегоКолонтитула, ОбластьНижнегоКолонтитула,
ОбластьШапкаТаблицы, НомерСтраницы);
КонецЦикла;
Параметр ЗапретВисячихШапокТаблицы в функции задан безусловно в Истина, но при использовании данной функции Вы можете вынести параметр за ее пределы и сделать настраиваемым, главное, что есть такая возможность.
Пример повтора шапки таблицы:
Почему в задаче был упомянут корректный вывод нижнего колонтитула на последней странице? Потому что при тех способах, что советовали в других статьях (например, просто добавить область нижнего колонтитула к последней выводимой области в документе) получалось, что колонтитул отображался не в самом низу страницы, а там, где закончился документ (например, где-нибудь посередине, а бывало и в вверху). В указанной функции для этого используется область пустой строки (т.е. последняя страница "дополняется" до самого низа пустыми строками и только в самом конце выводится нижний колонтитул).
Вот пример вывода последней страницы:
Поэтому, после вывода всех данных в табличный документ делаем завершающий вызов функции, если нужно корректно завершить страницу с нижним колонтитулом:
// завершающий вывод
НомерСтраницы = ВыводВТабДокСКолонтитулами(ТабДок,,
ОбластьПустойСтроки,, ОбластьНижнегоКолонтитула,, НомерСтраницы);
Полный пример:
Пример использования функции
Функция СформироватьПечатнуюФорму()
// Получение макета.
Макет = Документы.п_ВыпискаИзЭлектроннойЗачетнойКнижки.ПолучитьМакет("МакетСКолонтитулами");
ОбластьВерхнегоКолонтитула = Макет.ПолучитьОбласть("ВерхнийКолонтитул");
ОбластьНижнегоКолонтитула = Макет.ПолучитьОбласть("НижнийКолонтитул");
ОбластьПустойСтроки = Макет.ПолучитьОбласть("ПустаяСтрока");
//Получаем данные для QR-кода
QRCode = Новый Картинка(УправлениеПечатью.ДанныеQRКода("СтрокаДляКодирования", 0, 100));
ОбластьНижнегоКолонтитула.Параметры.QRCode = QRCode;
ТабДок = Новый ТабличныйДокумент;
// размер и параметры страницы (необходимо для вычислений страниц)
ТабДок.РазмерСтраницы = "A4";
ТабДок.ОриентацияСтраницы = ОриентацияСтраницы.Ландшафт;
ТабДок.МасштабПечати = 100; // 100%
ТабДок.ПолеСверху = 10;
ТабДок.ПолеСнизу = 5;
ТабДок.ПолеСлева = 15;
ТабДок.ПолеСправа = 10;
НомерСтраницы = 1;
// Первый вывод верхнего колонтитула.
ТабДок.Вывести(ОбластьВерхнегоКолонтитула);
ПараметрыОтчетаВВидеСтруктуры = Новый Структура("ФамилияИмяОтчество, НомерДокумента",
ЭтотОбъект.ФизическоеЛицо, ЭтотОбъект.ЗачетнаяКнига);
Область = Макет.ПолучитьОбласть("ШапкаДокумента");
// заполняем значениями параметров.
Область.Параметры.Заполнить(ПараметрыОтчетаВВидеСтруктуры);
// Выводим в табличный документ.
НомерСтраницы = ВыводВТабДокСКолонтитулами(ТабДок, Область,
ОбластьПустойСтроки, ОбластьВерхнегоКолонтитула,
ОбластьНижнегоКолонтитула,, НомерСтраницы);
// Таблица курсовых работ.
Если ЭтотОбъект.КурсовыеРаботы.Количество() > 0 Тогда
ОбластьШапкаТаблицы = Макет.ПолучитьОбласть("КурсовыеРаботыШапкаТаблицы");
// Вывод шапки таблицы (с проверкой ЗапретВисячихШапокТаблицы)
НомерСтраницы = ВыводВТабДокСКолонтитулами(ТабДок, ОбластьШапкаТаблицы,
ОбластьПустойСтроки, ОбластьВерхнегоКолонтитула,
ОбластьНижнегоКолонтитула, ОбластьШапкаТаблицы, НомерСтраницы);
// Построчный вывод строк таблицы с данными.
Для каждого СтрокаКР из ЭтотОбъект.КурсовыеРаботы Цикл
Область = Макет.ПолучитьОбласть("КурсовыеРаботыДанные");
Область.Параметры.Заполнить(СтрокаКР); // заполняем значениями параметров.
// Вывод очередной строки таблицы с проверкой переноса и повтором шапки таблицы.
НомерСтраницы = ВыводВТабДокСКолонтитулами(ТабДок, Область,
ОбластьПустойСтроки, ОбластьВерхнегоКолонтитула,
ОбластьНижнегоКолонтитула, ОбластьШапкаТаблицы, НомерСтраницы);
КонецЦикла;
КонецЕсли;
Область = Макет.ПолучитьОбласть("Подвал");
НомерСтраницы = ВыводВТабДокСКолонтитулами(ТабДок, Область,
ОбластьПустойСтроки, ОбластьВерхнегоКолонтитула,
ОбластьНижнегоКолонтитула,, НомерСтраницы);
// Завершающий вывод.
НомерСтраницы = ВыводВТабДокСКолонтитулами(ТабДок,, ОбластьПустойСтроки,,
ОбластьНижнегоКолонтитула,, НомерСтраницы);
Возврат ТабДок;
КонецФункции
Скачать готовый пример отчета с данной функцией можно здесь (в примере используется тот же код, что представлен в статье):
Произвольные колонтитулы и повтор шапки таблицы в табличном документе (пример в виде внешнего отчета)
См. также:
Возможно будут интересны статьи: