Как правильно вывести результаты запроса в печатную форму таблицы в 1С 7.7 и избежать пустых ячеек?

Программист 1С v7.7 Управленческий учет Торговля и дистрибуция
← На главную

Разработка отчетов и печатных форм в платформе 1С:Предприятие 7.7 имеет свои уникальные особенности, которые часто вызывают трудности у начинающих программистов. Типичный сценарий: запрос отрабатывает без ошибок, макет печатной формы («Таблица») открывается, но вместо заполненных строк мы видим либо пустые ячейки, либо бесконечное дублирование пустых областей.

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

---

Анализ проблемы: почему ячейки печатной формы выводятся пустыми?

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


Пока Запрос.Группировка(1) = 1 Цикл
    Таб.ВывестиСекцию("Номенк");
    Товар = Запрос.Номенк;
    Пока Запрос.Группировка(2) = 1 Цикл
        Таб.ВывестиСекцию("ЦенаПрод");
        Цена = Запрос.ЦенаПрод;
    КонецЦикла;
КонецЦикла;

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

Когда платформа 1С 7.7 выполняет метод Таб.ВывестиСекцию("ИмяСекции"), она мгновенно обращается к текущему контексту программного модуля (переменным, функциям), чтобы вычислить значения, которые прописаны в ячейках выводимой секции макета (если в свойствах ячейки выбран тип «Выражение» или «Шаблон»).

Если мы пишем:


Таб.ВывестиСекцию("Номенк"); // Платформа пытается прочитать значение переменной "Товар"
Товар = Запрос.Номенк;       // Переменная заполняется ПОСЛЕ того, как секция уже выведена!

В момент вывода секции переменная Товар еще пуста (или содержит значение из предыдущей итерации цикла). В результате на печать выводится пустая область, и только после этого в переменную записывается нужное значение, которое уже нигде не используется.

---

Способ 1. Исправление порядка заполнения переменных (Классический подход)

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

Давайте перепишем код обхода группировок запроса правильно:


// Сначала подготавливаем таблицу
Таб = СоздатьОбъект("Таблица");
Таб.ИсходнаяТаблица("Выполнение");
Таб.ВывестиСекцию("Шапка");

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

Таб.ВывестиСекцию("Подвал");
Таб.ТолькоПросмотр(1);
Таб.Показать("Вывод результатов запроса");

Обратите внимание: функция остатка КоличОст, объявленная в запросе как Функция КоличОст = КонОст(Колич);, рассчитывается на уровне группировок. Доступ к ее значению мы получаем через объект запроса: Запрос.КоличОст.

---

Способ 2. Вывод данных без использования промежуточных переменных (Лайфхак)

Мало кто из начинающих разработчиков знает, что в 1С 7.7 вообще необязательно создавать в коде промежуточные переменные вида Товар, Цена или Остаток и присваивать им значения в цикле.

Мы можем обратиться к результатам выполнения запроса напрямую из ячеек макета печатной формы. Для этого выполним следующие шаги:

  1. Откроем макет печатной формы (таблицу) в конфигураторе.
  2. Выделим ячейку, где должно выводиться наименование номенклатуры. Откроем её свойства (клавиша Alt+Enter).
  3. Установим тип ячейки: Выражение.
  4. В поле ввода выражения запишем напрямую: Запрос.Номенк.
  5. Для ячейки с ценой укажем выражение: Запрос.ЦенаПрод.
  6. Для ячейки с остатком укажем выражение: Запрос.КоличОст.

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


Пока Запрос.Группировка(1) = 1 Цикл
    Таб.ВывестиСекцию("Номенк"); // Платформа сама обратится к Запрос.Номенк
    
    Пока Запрос.Группировка(2) = 1 Цикл
        Таб.ВывестиСекцию("Цена"); // Платформа сама возьмет Запрос.ЦенаПрод и Запрос.КоличОст
    КонецЦикла;
КонецЦикла;

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

---

Способ 3. Выгрузка результатов запроса в Таблицу Значений (Альтернатива без вложенных циклов)

Если в вашем запросе много группировок, написание большого количества вложенных циклов Пока Запрос.Группировка(...) = 1 может сильно усложнить код и привести к логическим ошибкам (как это произошло у автора темы в сообщении 11, где он запутался и попытался вызвать несуществующую третью группировку).

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

Рассмотрим, как реализовать этот подход по шагам:


// Выполняем запрос
Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
    Предупреждение("Запрос не выполнен!");
    Возврат;
EndЕсли;

// Создаем Таблицу Значений и выгружаем в нее результаты
ТЗ = СоздатьОбъект("ТаблицаЗначений");
// Второй параметр "1" означает, что мы выгружаем результаты с группировками в плоскую таблицу
Запрос.Выгрузить(ТЗ, 1, 1); 

// Настраиваем печатную форму
Таб = СоздатьОбъект("Таблица");
Таб.ИсходнаяТаблица("ПечатьИзТЗ");
Таб.ВывестиСекцию("Шапка");

// Обходим строки Таблицы Значений в одном цикле
ТЗ.ВыбратьСтроки();
Пока ТЗ.ПолучитьСтроку() = 1 Цикл
    // В процессе обхода ТЗ колонки становятся доступны как свойства строки
    Товар = ТЗ.Номенк;
    Цена  = ТЗ.ЦенаПрод;
    Остаток = ТЗ.КоличОст;
    
    // Выводим универсальную строку нашей таблицы
    Таб.ВывестиСекцию("СтрокаТаблицы");
КонецЦикла;

Таб.ВывестиСекцию("Подвал");
Таб.ТолькоПросмотр(1);
Таб.Показать("Печать результатов из ТЗ");

Преимущества данного метода:

---

Рекомендация: использование Конструктора выходных форм

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

Чтобы запустить его:

  1. Установите курсор в теле процедуры модуля, где хотите разместить код.
  2. Нажмите правую кнопку мыши и выберите пункт "Конструктор запроса...".
  3. На вкладке настройки вывода обязательно установите галочку "Создать печатную форму" (или "Обработка результатов").

Конструктор автоматически сгенерирует безошибочный текст запроса, создаст макет таблицы со всеми необходимыми секциями («Шапка», секции для группировок, «Подвал»), пропишет правильные выражения внутри ячеек макета и сформирует эталонный код обхода группировок. Вам останется лишь визуально подредактировать ширину колонок и шрифты в макете.

← На главную