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