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

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

Приветствуем вас, уважаемые разработчики! Вывод данных из запроса в макет табличного документа — это фундаментальная задача в среде «1С:Предприятие», с которой регулярно сталкивается каждый программист. Начинающие разработчики часто совершают типовые ошибки, пытаясь вручную написать алгоритм заполнения параметров и вывода областей. В результате печатная форма либо отображается пустой, либо выводит только одну (первую или последнюю) строку, либо вообще вызывает критические ошибки выполнения кода.

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

Разбор критических ошибок в исходном коде

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


Процедура КнопкаВыполнитьНажатие(Кнопка)
    Запрос=Новый Запрос;
    Запрос.Текст= "ВЫБРАТЬ ...";
    // ... установка параметров ...
    Результат=Запрос.Выполнить().Выбрать();
    Результат.Следующий();
  
    Макет=ПолучитьМакет("Макет");
    ОбластьМакета=Макет.ПолучитьОбласть("Заголовок");
    ОбластьМакета=Макет.ПолучитьОбласть("Шапка");
    ОбластьМакета=Макет.ПолучитьОбласть("Данные");
    ОбластьМакета.Параметры.Заказ=Результат.Заказ;
    ОбластьМакета.Параметры.Маршрутник=Результат.Маршрутник;
КонецПроцедуры

Проанализируем эту ситуацию по шагам и выделим четыре ключевые ошибки:

  1. Перезапись переменной области макета. Обратите внимание на строки, где получается область макета. Переменная ОбластьМакета инициализируется три раза подряд. Сначала в нее помещается область «Заголовок», затем она заменяется областью «Шапка», а в конце — областью «Данные». Предыдущие области просто уничтожаются в оперативной памяти компьютера. Для каждой уникальной секции макета необходимо использовать собственную отдельную переменную.
  2. Отсутствие целевого табличного документа. Объект типа Макет — это всего лишь шаблон, чертеж будущей формы. Чтобы пользователь увидел результат на экране, нам необходим «чистый лист бумаги» — объект класса ТабличныйДокумент. Именно в него методом Вывести() последовательно переносятся подготовленные области макета. В коде автора табличный документ даже не создается.
  3. Отсутствие цикла обхода выборки. Конструкция Результат.Следующий() вызывается ровно один раз. Метод Следующий() позиционирует указатель выборки на первую строку данных и возвращает Истина, если данные есть. Если запрос возвращает множество строк, то без использования цикла Пока ... Цикл все последующие строки (начиная со второй) будут проигнорированы.
  4. Некорректная группировка в запросе. Использование секции СГРУППИРОВАТЬ ПО без использования агрегатных функций (таких как СУММА, КОЛИЧЕСТВО, СРЕДНЕЕ) является избыточным и неоптимальным. Если целью является исключение дублирования строк в выборке, гораздо правильнее использовать ключевое слово РАЗЛИЧНЫЕ в самом начале инструкции ВЫБРАТЬ.

Теперь, когда мы выяснили все причины некорректного поведения кода, перейдем к реализации правильных и надежных алгоритмов.

Решение №1: Классический вариант для Обычных форм (1С 8.2 / 8.3)

Рассмотрим подробнее исправленный вариант процедуры для обычного приложения. Здесь мы создаем табличный документ, последовательно выводим в него статические области заголовка и шапки таблицы, а затем в цикле заполняем и выводим динамические строки данных.


Процедура КнопкаВыполнитьНажатие(Кнопка)
    
    // 1. Создаем результирующий табличный документ, который отобразится пользователю
    ТабДок = Новый ТабличныйДокумент;
    
    // 2. Получаем макет обработки/документа
    Макет = ПолучитьМакет("Макет");
    
    // 3. Получаем статичные области макета и сразу выводим их в табличный документ
    ОбластьЗаголовок = Макет.ПолучитьОбласть("Заголовок");
    ТабДок.Вывести(ОбластьЗаголовок);
    
    ОбластьШапка = Макет.ПолучитьОбласть("Шапка");
    ТабДок.Вывести(ОбластьШапка);
    
    // 4. Подготавливаем область для вывода строк таблицы
    ОбластьДанные = Макет.ПолучитьОбласть("Данные");
    
    // 5. Инициализируем и настраиваем запрос
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ РАЗЛИЧНЫЕ
        |   МаршрутныйЛистЗаказы.Ссылка КАК Маршрутник,
        |   МаршрутныйЛистЗаказы.Заказ.Ссылка КАК Заказ
        |ИЗ
        |   Документ.МаршрутныйЛист.Заказы КАК МаршрутныйЛистЗаказы
        |ГДЕ
        |   МаршрутныйЛистЗаказы.Заказ.Дата МЕЖДУ &НачалоПериода И &КонецПериода";
    
    // Устанавливаем границы периода с приведением к началу и концу дня
    Запрос.УстановитьПараметр("НачалоПериода", НачалоДня(НачалоПериода));
    Запрос.УстановитьПараметр("КонецПериода", КонецДня(КонецПериода));
    
    РезультатЗапроса = Запрос.Выполнить();
    
    // Проверяем, есть ли данные в результате запроса
    Если Не РезультатЗапроса.Пустой() Тогда
        
        Выборка = РезультатЗапроса.Выбрать();
        
        // 6. Запускаем цикл обхода всех полученных записей
        Пока Выборка.Следующий() Цикл
            
            // Заполняем параметры области макета данными из текущей строки выборки
            ОбластьДанные.Параметры.Заказ = Выборка.Заказ;
            ОбластьДанные.Параметры.Маршрутник = Выборка.Маршрутник;
            
            // Выводим подготовленную область в итоговый документ
            ТабДок.Вывести(ОбластьДанные);
            
        КонецЦикла;
        
    КонецЕсли;
    
    // 7. Показываем сформированный табличный документ пользователю на экране
    ТабДок.Показать("Маршрутные листы по заказам");
    
КонецПроцедуры

Решение №2: Современный вариант для Управляемых форм (1С 8.3)

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

Код в модуле управляемой формы будет выглядеть следующим образом:


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

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

Полезные лайфхаки при разработке печатных форм

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

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

← На главную