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

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

В процессе разработки в среде 1С:Предприятие 8.3 программисты часто сталкиваются с задачей вывода на печать таблицы значений (ТЗ), которая формируется динамически непосредственно в форме обработки. Стандартная системная кнопка "Вывести список" решает эту задачу лишь частично, так как она не позволяет применить к печатной форме сложное форматирование, настроить группировки, рассчитать итоги по колонкам или кастомизировать макет под требования корпоративных стандартов.

В этой статье мы подробно разберем наиболее эффективные и современные способы решения этой задачи на управляемых формах. Мы проанализируем архитектурные нюансы платформы 1С 8.3, изучим программный вывод через Систему компоновки данных (СКД) с использованием внешнего набора данных, научимся правильно работать с временным хранилищем и рассмотрим традиционный способ вывода ТЗ «ручками» с помощью областей макета.

Способ 1. Использование СКД и внешнего набора данных («Набор данных - объект»)

Этот способ является наиболее гибким, так как он позволяет использовать всю мощь Системы компоновки данных: автоматическое построение иерархии, группировки, условное оформление и подсчет итогов без написания сотен строк кода ручной прорисовки. Суть метода заключается в том, что мы описываем структуру нашей таблицы в макете компоновки данных, а затем передаем готовую ТЗ в качестве внешнего источника.

Давайте разберем по шагам, как реализовать этот механизм программно.

Шаг 1. Создание макета СКД в обработке

В конфигураторе откроем нашу обработку, перейдем на вкладку «Макеты» и добавим новый макет с типом СхемаКомпоновкиДанных. Назовем его, например, ОсновнаяСхемаКомпоновкиДанных. В открывшемся конструкторе выполним следующие действия:

  1. Добавим новый набор данных с типом "Набор данных - объект".
  2. В поле "Имя объекта содержащего данные" укажем уникальный идентификатор источника, например, ВнешняяТаблица. Этот идентификатор крайне важен — именно по нему мы будем передавать ТЗ из кода.
  3. Добавим поля набора данных. Имена полей должны символ в символ (включая регистр букв) совпадать с именами колонок нашей таблицы значений. Для каждого поля обязательно укажем понятный заголовок и тип данных.
  4. Перейдем на вкладку «Настройки» и добавим в структуру отчета группировку «Детальные записи», а на вкладке «Выбранные поля» выберем те поля, которые должны отображаться в печатной форме.

Шаг 2. Строгая типизация колонок таблицы значений

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

Рассмотрим пример правильной инициализации и заполнения таблицы значений в коде формы:


&НаСервере
Функция ПолучитьТаблицуДляПечати()
    
    // Создаем таблицу значений
    ТЗ = Новый ТаблицаЗначений;
    
    // Обязательно задаем строгие типы для колонок
    МассивТиповСтрока = Новый Массив;
    МассивТиповСтрока.Добавить(Тип("Строка"));
    ОписаниеТиповСтрока = Новый ОписаниеТипов(МассивТиповСтрока, , Новый КвалификаторыЧисла(100));
    
    МассивТиповЧисло = Новый Массив;
    МассивТиповЧисло.Добавить(Тип("Число"));
    ОписаниеТиповЧисло = Новый ОписаниеТипов(МассивТиповЧисло, , , Новый КвалификаторыЧисла(15, 2));
    
    ТЗ.Колонки.Добавить("НоменклатураКод", ОписаниеТиповСтрока);
    ТЗ.Колонки.Добавить("НоменклатураНаименование", ОписаниеТиповСтрока);
    ТЗ.Колонки.Добавить("Количество", ОписаниеТиповЧисло);
    ТЗ.Колонки.Добавить("Сумма", ОписаниеТиповЧисло);
    
    // Заполняем таблицу тестовыми данными
    НоваяСтрока = ТЗ.Добавить();
    НоваяСтрока.НоменклатураКод = "00-000001";
    НоваяСтрока.НоменклатураНаименование = "Пылесос бытовой";
    НоваяСтрока.Количество = 2;
    НоваяСтрока.Сумма = 15000;
    
    НоваяСтрока = ТЗ.Добавить();
    НоваяСтрока.НоменклатураКод = "00-000002";
    НоваяСтрока.НоменклатураНаименование = "Микроволновая печь";
    НоваяСтрока.Количество = 1;
    НоваяСтрока.Сумма = 8500;
    
    Возврат ТЗ;
    
КонецФункции

Шаг 3. Программный вывод макета СКД на форму

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


&НаСервере
Процедура СформироватьПечатнуюФормуНаСервере(РезультатТабДок)
    
    // Очищаем табличный документ перед выводом
    РезультатТабДок.Очистить();
    
    // Получаем объект обработки для доступа к макетам
    ОбработкаОбъект = РеквизитФормыВЗначение("Объект");
    
    // Получаем схему компоновки данных из макета
    СхемаКомпоновкиДанных = ОбработкаОбъект.ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
    
    // Получаем настройки по умолчанию
    Настройки = СхемаКомпоновкиДанных.НастройкиПоУмолчанию;
    
    // Инициализируем внешний набор данных и передаем туда нашу ТЗ
    ВнешниеНаборыДанных = Новый Структура;
    // Имя ключа структуры должно строго совпадать с "Именем объекта содержащего данные" в СКД!
    ВнешниеНаборыДанных.Вставить("ВнешняяТаблица", ПолучитьТаблицуДляПечати());
    
    // Создаем объект для хранения данных расшифровки
    ДанныеРасшифровки = Новый ДанныеРасшифровкиКомпоновкиДанных;
    
    // Формируем макет компоновки с помощью компоновщика макета
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, ДанныеРасшифровки);
    
    // Инициализируем процессор компоновки данных
    ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных, ДанныеРасшифровки);
    
    // Выводим результат в табличный документ на форме
    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
    ПроцессорВывода.УстановитьДокумент(РезультатТабДок);
    ПроцессорВывода.Вывести(ПроцессорКомпоновкиДанных);
    
КонецПроцедуры

Способ 2. Правильное использование Временного Хранилища

Часто архитектура приложения требует, чтобы печать происходила не в форме самой обработки, а в отдельной форме отчета. В этом случае нам необходимо передать таблицу значений с клиента на сервер другого объекта. Напрямую передать ТЗ через клиент-серверную границу нельзя, поэтому мы должны использовать объект ВременноеХранилище.

Рассмотрим критическую ошибку, которую часто совершают начинающие разработчики. При помещении данных во временное хранилище они пишут следующий код:


// ОШИБОЧНЫЙ ВАРИАНТ!
Адрес = ПоместитьВоВременноеХранилище(МояТЗ, Новый УникальныйИдентификатор);

В чем заключается ошибка? Если в качестве второго параметра метода ПоместитьВоВременноеХранилище передать новый уникальный идентификатор, то адрес временного хранилища становится "автономным" и не привязывается к контексту текущей формы. Платформа 1С может очистить эти данные сразу же после завершения текущего серверного вызова. В результате при попытке прочитать ТЗ в форме отчета программа выдаст критическую ошибку: "Данные во временном хранилище не найдены или устарели".

Проанализируем правильный вариант реализации этой схемы:


&НаКлиенте
Процедура ПередатьТЗиОткрытьОтчет()
    
    // Помещаем таблицу во временное хранилище с привязкой к уникальному идентификатору ТЕКУЩЕЙ формы
    АдресХранилища = ПоместитьТЗВоВременноеХранилищеНаСервере();
    
    // Передаем адрес хранилища в параметрах открытия формы отчета
    ПараметрыОткрытия = Новый Структура;
    ПараметрыОткрытия.Вставить("АдресДанныхПечати", АдресХранилища);
    
    ОткрытьФорму("Отчет.МойОтчетДляПечати.Форма", ПараметрыОткрытия);
    
КонецПроцедуры

&НаСервере
Функция ПоместитьТЗВоВременноеХранилищеНаСервере()
    
    ТЗ = ПолучитьТаблицуДляПечати(); // Ваша сформированная таблица
    
    // ПРАВИЛЬНО: Привязываем адрес к УИД этой формы
    Возврат ПоместитьВоВременноеХранилище(ТЗ, ЭтаФорма.УникальныйИдентификатор);
    
КонецФункции

В модуле формы отчета, который мы открываем, в обработчике события ПриСозданииНаСервере мы сможем безопасно прочитать эти данные и использовать их для построения отчета:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    Если Параметры.Свойство("АдресДанныхПечати") Тогда
        
        // Извлекаем таблицу значений из временного хранилища
        ТаблицаДанных = ПолучитьИзВременногоХранилища(Параметры.АдресДанныхПечати);
        
        Если ТипЗнч(ТаблицаДанных) = Тип("ТаблицаЗначений") Тогда
            // Выполняем построение отчета на основе полученной таблицы
            ПостроитьОтчетПоТаблице(ТаблицаДанных);
        КонецЕсли;
        
    КонецЕсли;
    
КонецПроцедуры

Способ 3. Полностью программное создание СКД (без макета в Конфигураторе)

Что делать, если структура таблицы значений на форме заранее неизвестна и колонки формируются динамически в зависимости от настроек пользователя? В таких условиях создать статический макет в Конфигураторе невозможно. Нам на помощь приходит полностью программное формирование схемы компоновки данных.

Разберем детальный пример, как программно создать схему, добавить в нее поля на основе колонок ТЗ и вывести результат:


&НаСервере
Процедура ПрограммныйВыводДинамическойТЗ(РезультатТабДок, ИсточникТЗ)
    
    РезультатТабДок.Очистить();
    
    // 1. Создаем схему компоновки данных программно
    СхемаКомпоновкиДанных = Новый СхемаКомпоновкиДанных;
    
    // Добавляем источник данных "ЛокальнаяБаза"
    ИсточникДанных = СхемаКомпоновкиДанных.ИсточникиДанных.Добавить();
    ИсточникДанных.Имя = "ЛокальныйИсточник";
    ИсточникДанных.ТипИсточникаДанных = "Local";
    
    // Добавляем новый набор данных - объект
    НаборДанных = СхемаКомпоновкиДанных.НаборыДанных.Добавить(Тип("НаборДанныхОбъектКомпоновкиДанных"));
    НаборДанных.Имя = "ДинамическийНаборДанных";
    НаборДанных.ИмяОбъекта = "ВнешняяТаблицаДанных";
    НаборДанных.ИсточникДанных = "ЛокальныйИсточник";
    
    // 2. Настраиваем структуру колонок на основе переданной ТЗ
    Для Каждого Колонка Из ИсточникТЗ.Колонки Цикл
        
        ПолеНабора = НаборДанных.Поля.Добавить(Тип("ПолеНабораДанныхСхемыКомпоновкиДанных"));
        ПолеНабора.Имя = Колонка.Имя;
        ПолеНабора.Поле = Колонка.Имя;
        ПолеНабора.Заголовок = ?(ЗначениеЗаполнено(Колонка.Заголовок), Колонка.Заголовок, Колонка.Имя);
        ПолеНабора.ТипЗначения = Колонка.ТипЗначения;
        
    КонецЦикла;
    
    // 3. Задаем настройки по умолчанию
    Настройки = СхемаКомпоновкиДанных.НастройкиПоУмолчанию;
    
    // Создаем структуру вывода (Детальные записи)
    Группировка = Настройки.Структура.Добавить(Тип("ГруппировкаКомпоновкиДанных"));
    Группировка.Использование = Истина;
    
    АвтоВыборПолей = Группировка.Выбор.Элементы.Добавить(Тип("АвтоВыбранноеПолеКомпоновкиДанных"));
    АвтоВыборПолей.Использование = Истина;
    
    // Добавляем выбранные поля в основные настройки
    Для Каждого Колонка Из ИсточникТЗ.Колонки Цикл
        ВыбранноеПоле = Настройки.Выбор.Элементы.Добавить(Тип("ВыбранноеПолеКомпоновкиДанных"));
        ВыбранноеПоле.Использование = Истина;
        ВыбранноеПоле.Поле = Новый ПолеКомпоновкиДанных(Колонка.Имя);
    КонецЦикла;
    
    // 4. Компоновка и вывод на экран
    ВнешниеНаборыДанных = Новый Структура;
    ВнешниеНаборыДанных.Вставить("ВнешняяТаблицаДанных", ИсточникТЗ);
    
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки);
    
    ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных);
    
    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
    ПроцессорВывода.УстановитьДокумент(РезультатТабДок);
    ПроцессорВывода.Вывести(ПроцессорКомпоновки);
    
КонецПроцедуры

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

Способ 4. Традиционный вывод «ручками» через макет Табличного Документа

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

В таких случаях идеальным решением остается классический вывод ТЗ секциями. Давайте рассмотрим, как это реализовать.

Сначала создадим обычный макет с типом "Табличный документ" в нашей обработке. Назовем его МакетПечатиТЗ. Разделим его горизонтальными именованными областями:

Напишем процедуру заполнения и вывода этого макета:


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

Почему не работает Построитель отчета на Управляемых Формах?

В старых конфигурациях 1С (на Обычных формах) разработчики часто использовали объект ПостроительОтчета для быстрой печати таблиц значений. Однако при переходе на Управляемые формы этот метод перестал работать. Выясним причину:

Поэтому в современной разработке на платформе 1С 8.3 настоятельно рекомендуется полностью отказаться от использования ПостроительОтчета в пользу универсальных механизмов СКД или прямого вывода макетов.

Резюме и рекомендации

Мы проанализировали основные способы вывода таблиц значений на печать. Подведем итог, какой инструмент лучше выбрать:

  1. Если структура таблицы статична и вам требуются сложные группировки, итоги и пользовательские настройки — используйте Способ 1 (СКД с макетом).
  2. Если печать должна происходить в отдельной форме отчета — используйте Способ 2 (Временное хранилище) с обязательной привязкой к уникальному идентификатору формы-источника.
  3. Если структура таблицы меняется на лету и колонки создаются динамически — вашим лучшим выбором будет Способ 3 (Программное создание схемы СКД).
  4. Если требуется создать строго регламентированную печатную форму со сложным дизайном — используйте классический Способ 4 (Ручной обход ТЗ через макет).
← На главную