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