В процессе разработки в среде «1С:Предприятие» программисты часто сталкиваются с задачей вывода подготовленных данных в печатную форму. Традиционный сценарий выглядит так: разработчик получает данные с помощью запроса, при необходимости обрабатывает их во временной таблице или выгружает в объект ТаблицаЗначений, после чего результат нужно представить пользователю в виде красивого и структурированного табличного документа.
В данной статье мы подробно разберем несколько практических способов вывода данных из запроса или Таблицы Значений (ТЗ) в макет печатной формы. Мы пройдем путь от простого классического перебора строк до продвинутых методов динамической генерации таблиц и использования Системы Компоновки Данных (СКД), а также затронем важные вопросы оптимизации программного кода.
Этот метод является наиболее распространенным и применяется тогда, когда структура печатной формы известна заранее и создана в конфигураторе в виде макета. Мы получаем макет, разбиваем его на строки-области (Шапка, Строка, Подвал) и последовательно выводим их в результирующий табличный документ.
Разберем по шагам классический алгоритм вывода:
ТабличныйДокумент, который и будет показан пользователю.Вывести().Рассмотрим пример кода, реализующий данный алгоритм:
// 1. Получаем данные (в нашем примере выгружаем запрос в Таблицу Значений)
ТаблицаДанных = Запрос.Выполнить().Выгрузить();
// 2. Инициализируем табличный документ и получаем макет
ТабДок = Новый ТабличныйДокумент;
ТабДок.Очистить(); // Очищаем документ перед заполнением
Макет = ПолучитьМакет("ПечатнаяФормаРеестр");
// 3. Получаем области макета
ОбластьЗаголовок = Макет.ПолучитьОбласть("Заголовок");
ОбластьШапкаТаблицы = Макет.ПолучитьОбласть("ШапкаТаблицы");
ОбластьСтрока = Макет.ПолучитьОбласть("Строка");
ОбластьПодвал = Макет.ПолучитьОбласть("Подвал");
// 4. Выводим статичную шапку документа
ОбластьЗаголовок.Параметры.ДатаОтчета = Формат(ТекущаяДата(), "ДЛФ=Д");
ТабДок.Вывести(ОбластьЗаголовок);
ТабДок.Вывести(ОбластьШапкаТаблицы);
// 5. Запускаем цикл по строкам таблицы значений для вывода детальных записей
Для Каждого СтрокаДанных Из ТаблицаДанных Цикл
// Заполняем параметры области детальных записей
ОбластьСтрока.Параметры.Номенклатура = СтрокаДанных.Номенклатура;
ОбластьСтрока.Параметры.Количество = СтрокаДанных.Количество;
ОбластьСтрока.Параметры.Разница = СтрокаДанных.Разница;
// Выводим заполненную область в итоговый документ
ТабДок.Вывести(ОбластьСтрока);
КонецЦикла;
// 6. Выводим подвал с итогами
ТабДок.Вывести(ОбластьПодвал);
// 7. Показываем готовый документ пользователю
ТабДок.Показать("Реестр документов");
Важная оптимизация: Если в вашей таблице содержится 10, 20 или более колонок, ручное присвоение каждого параметра в цикле (как в шаге 5) превращается в рутину и загромождает код. Платформа 1С предлагает встроенный метод автоматического сопоставления имен параметров области и колонок таблицы. Мы можем использовать метод Заполнить() у параметров области:
Для Каждого СтрокаДанных Из ТаблицаДанных Цикл
// Автоматическое заполнение всех параметров области одноименными колонками строки ТЗ
ОбластьСтрока.Параметры.Заполнить(СтрокаДанных);
ТабДок.Вывести(ОбластьСтрока);
КонецЦикла;
Этот простой прием сокращает десятки строк кода и делает его устойчивым к изменениям: если вы добавите новую колонку в запрос и макет с тем же именем, код заполнения менять не придется.
Иногда возникает задача вывести таблицу данных, структура которой заранее неизвестна, либо колонок слишком много и создавать под них фиксированный макет в конфигураторе нецелесообразно. В таких случаях мы можем сформировать макет "на лету" программно, напрямую обращаясь к ячейкам объекта ТабличныйДокумент.
Выясним, как реализовать этот алгоритм динамически:
ТабДок = Новый ТабличныйДокумент;
// Шаг 1. Формируем шапку таблицы на основе колонок ТЗ
НомерКолонки = 1;
Для Каждого Колонка Из ТаблицаДанных.Колонки Цикл
ЯчейкаШапки = ТабДок.Область(1, НомерКолонки);
// Используем заголовок колонки, если он задан, иначе ее имя
ЯчейкаШапки.Текст = ?(ЗначениеЗаполнено(Колонка.Заголовок), Колонка.Заголовок, Колонка.Имя);
// Оформляем шапку: делаем шрифт жирным и устанавливаем границы
ЯчейкаШапки.Шрифт = Новый Шрифт(ЯчейкаШапки.Шрифт, , , Истина);
ЯчейкаШапки.ГраницаСнизу = Новый Линия(ТипЛинииСтенкиТабличногоДокумента.Сплошная, 2);
НомерКолонки = НомерКолонки + 1;
КонецЦикла;
// Шаг 2. Выводим строки с данными
ТекущаяСтрока = 2;
Для Каждого СтрокаТЗ Из ТаблицаДанных Цикл
НомерКолонки = 1;
Для Каждого Колонка Из ТаблицаДанных.Колонки Цикл
ЯчейкаДанных = ТабДок.Область(ТекущаяСтрока, НомерКолонки);
ЯчейкаДанных.Текст = Строка(СтрокаТЗ[Колонка.Имя]);
// Легкая рамка для ячеек данных
ЯчейкаДанных.ГраницаСлева = Новый Линия(ТипЛинииСтенкиТабличногоДокумента.Тонкая);
ЯчейкаДанных.ГраницаСправа = Новый Линия(ТипЛинииСтенкиТабличногоДокумента.Тонкая);
ЯчейкаДанных.ГраницаСнизу = Новый Линия(ТипЛинииСтенкиТабличногоДокумента.Тонкая);
НомерКолонки = НомерКолонки + 1;
КонецЦикла;
ТекущаяСтрока = ТекущаяСтрока + 1;
КонецЦикла;
// Шаг 3. Настройка отображения сетки и автоширины колонок
ТабДок.ОтображатьСетку = Ложь;
ТабДок.Показать("Произвольный отчет");
Этот способ незаменим при создании универсальных обработок выгрузки данных, административных отчетов и инструментов отладки.
Когда требуется не просто вывести плоскую таблицу, но и предоставить пользователю возможности группировки, сортировки, условного оформления и автоматического подсчета итогов, лучшим решением является использование СКД. В качестве источника данных для СКД мы можем передать уже готовую ТаблицуЗначений через механизм внешних наборов данных.
Проанализируем программную реализацию вывода ТЗ через СКД:
ВнешнийИсточникДанных.Программный код для вывода выглядит следующим образом:
// 1. Помещаем нашу ТЗ в структуру внешних наборов данных
ВнешниеДанные = Новый Структура;
ВнешниеДанные.Вставить("ВнешнийИсточникДанных", ТаблицаДанных);
// 2. Получаем схему и настройки по умолчанию
СхемаСКД = ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
НастройкиОтчета = СхемаСКД.НастройкиПоУмолчанию;
// 3. Выполняем компоновку макета
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаСКД, НастройкиОтчета);
// 4. Инициализируем процессор компоновки и передаем туда внешние данные
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, ВнешниеДанные);
// 5. Выводим результат в табличный документ
ТабДок = Новый ТабличныйДокумент;
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ТабДок);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
ТабДок.Показать("Отчет на СКД");
Если разработка ведется на старых версиях платформы или в конфигурации на обычных формах (например, УТ 10.3, УПП 1.3), можно воспользоваться объектом ПостроительОтчета. Это быстрый и простой способ визуализации ТЗ, требующий минимум кода.
ТабДок = Новый ТабличныйДокумент;
Построитель = Новый ПостроительОтчета;
// Назначаем источником данных нашу таблицу
Построитель.ИсточникДанных = Новый ОписаниеИсточникаДанных(ТаблицаДанных);
Построитель.ВыводитьЗаголовокОтчета = Ложь;
// Построитель автоматически генерирует макет и заполняет его
Построитель.Вывести(ТабДок);
ТабДок.Показать("Отчет Построителя");
Обратите внимание: объект ПостроительОтчета считается устаревшим и не рекомендуется к использованию в новых разработках под управляемое приложение. В современных конфигурациях его полностью заменяет СКД.
Рассматривая исходный пример кода, часто можно заметить избыточные громоздкие конструкции при установке параметров запроса. Посмотрим на классический пример "как делать не надо":
Если Не ЗначениеЗаполнено(Контрагент) Тогда
Запрос.УстановитьПараметр("НеПроверятьКонтрагент", Истина);
Иначе
Запрос.УстановитьПараметр("НеПроверятьКонтрагент", Ложь);
КонецЕсли;
Этот код легко оптимизировать до одной строки, напрямую передавая результат логического выражения в параметр запроса. Это делает код чистым, лаконичным и более простым для чтения:
Запрос.УстановитьПараметр("НеПроверятьКонтрагент", Не ЗначениеЗаполнено(Контрагент));
Запрос.УстановитьПараметр("НеПроверятьДата", Не (ЗначениеЗаполнено(ДатаНач) И ЗначениеЗаполнено(ДатаКон)));
Также обратите внимание на условия связи в запросах. Использование конструкции вида ПриходнаяНакладнаяСостав.Ссылка <> НЕОПРЕДЕЛЕНО в запросах 1С является избыточным для реквизитов ссылочного типа и может негативно влиять на производительность СУБД, отключая использование индексов. Подобные проверки лучше исключать из условий связи.