Как исправить ошибку «Переменная не определена» при работе с областями макета в 1С:Предприятие

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

При разработке печатных форм в системе «1С:Предприятие 8» программисты часто сталкиваются с необходимостью вывода сложных табличных документов. В процессе написания кода легко запутаться в именах переменных, областей и макетов, что приводит к досадным синтаксическим ошибкам. В этой статье мы подробно разберем одну из таких классических ошибок: «Переменная не определена» при попытке добавить область макета в массив для проверки вывода страниц. Мы выясним причину её возникновения, изучим стандарты именования переменных и рассмотрим правильные механизмы работы с печатными формами.

Введение и суть технической проблемы

Рассмотрим ситуацию, с которой столкнулся автор темы на форуме. При попытке запустить внешнюю печатную форму в толстом клиенте (обычное приложение) система выдает ошибку компиляции:

{ВнешняяОбработка.ОС_ИнвентаризацияИнвентаризационнаяОпись0504087.МодульОбъекта(249,34)}: Переменная не определена (ИтогиПоСтр)

Эта ошибка указывает на то, что на строке 249 встроенный язык 1С обнаружил идентификатор ИтогиПоСтр, который не был ранее объявлен в коде как переменная, процедура, функция или системный объект.

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


Макет = ПолучитьМакет("ИнвентаризационнаяОписьНФА_0504087_194н"); 

ОбластьМакетаТитул = Макет.ПолучитьОбласть("Титул"); 
ОбластьМакетаКомиссия = Макет.ПолучитьОбласть("Комиссия"); 
ОбластьМакетаКонцовкаТитула = Макет.ПолучитьОбласть("КонцовкаТитула"); 
ОбластьМакетаШапка = Макет.ПолучитьОбласть("Шапка"); 
ОбластьМакетаСтрока = Макет.ПолучитьОбласть("Строка"); 
ОбластьМакетаПустаяСтрока = Макет.ПолучитьОбласть("ПустаяСтрока"); 
ОбластьМакетаДопСтрока = Макет.ПолучитьОбласть("ДопСтрока"); 
ОбластьМакетаИтогоП = Макет.ПолучитьОбласть("ИтогоП"); 
ОбластьМакетаИтогиПоСтр = Макет.ПолучитьОбласть("ИтогиПоСтр"); 
ИтогоПоСтраницеЗаг = Макет.ПолучитьОбласть("ИтогоПоСтраницеЗаг"); 
ИтогоПоСтранице = Макет.ПолучитьОбласть("ИтогоПоСтранице"); 
ИтогоПоОписи = Макет.ПолучитьОбласть("ИтогоПоОписи"); 
ИтогоПоОписиЧисло = Макет.ПолучитьОбласть("ИтогоПоОписиЧисло"); 
Итоги = Макет.ПолучитьОбласть("Итоги"); 
Подвал = Макет.ПолучитьОбласть("Подвал"); 

СтрокаСПодвалом = Новый Массив; 
СтрокаСПодвалом.Добавить(ОбластьМакетаСтрока); 
СтрокаСПодвалом.Добавить(ИтогиПоСтр); // Ошибка возникает именно здесь!
СтрокаСПодвалом.Добавить(ИтогоПоСтранице); 
СтрокаСПодвалом.Добавить(ИтогоПоОписиЧисло); 

Анализ кода и поиск первопричины ошибки

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

ОбластьМакетаИтогиПоСтр = Макет.ПолучитьОбласть("ИтогиПоСтр");

В этой строке кода объявляется новая локальная переменная с именем ОбластьМакетаИтогиПоСтр. Именно в неё записывается ссылка на объект типа ОбластьЯчеекТабличногоДокумента, полученный из макета по его строковому имени (идентификатору) "ИтогиПоСтр".

Однако далее по тексту кода, при формировании массива СтрокаСПодвалом, программист пишет:

СтрокаСПодвалом.Добавить(ИтогиПоСтр);

Здесь и кроется главная ошибка. Разработчик перепутал имя переменной во встроенном языке (ОбластьМакетаИтогиПоСтр) и имя области в самом макете (строковый литерал "ИтогиПоСтр"). Так как переменная с именем ИтогиПоСтр в коде модуля не объявлялась и ей не присваивалось никакое значение, платформа 1С совершенно справедливо сообщает, что данная переменная не определена.

Разница между переменной и именем области макета

Для понимания сути проблемы важно четко разделять два понятия:

  1. Переменная во встроенном языке 1С — это именованная область памяти, которую мы объявляем в программном коде и используем для хранения данных (например, ОбластьМакетаИтогиПоСтр, Макет, СтрокаСПодвалом). Имена переменным разработчик может давать практически любые, соблюдая общие правила синтаксиса 1С.
  2. Имя области в макете — это строковый идентификатор (именованная группа строк/колонок), который задается визуально в конфигураторе в свойствах ячеек табличного документа. Этот идентификатор передается в метод ПолучитьОбласть() в качестве строкового параметра в кавычках (например, "ИтогиПоСтр").

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

Правильное исправление ошибки (Вариант 1)

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

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


// Объявляем переменную с префиксом ОбластьМакета
ОбластьМакетаИтогиПоСтр = Макет.ПолучитьОбласть("ИтогиПоСтр"); 

СтрокаСПодвалом = Новый Массив; 
СтрокаСПодвалом.Добавить(ОбластьМакетаСтрока); 
// Передаем правильную переменную в массив
СтрокаСПодвалом.Добавить(ОбластьМакетаИтогиПоСтр); 
СтрокаСПодвалом.Добавить(ИтогоПоСтранице); 
СтрокаСПодвалом.Добавить(ИтогоПоОписиЧисло); 

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

Альтернативный вариант исправления и его недостатки (Вариант 2)

В ходе обсуждения на форуме автор темы сообщил, что у него «заработало», когда он добавил следующую строчку кода:

ИтогиПоСтр = Макет.ПолучитьОбласть("ИтогиПоСтр");

Давайте проанализируем этот подход. Да, синтаксическая ошибка действительно исчезнет, поскольку в области видимости появится объявленная переменная ИтогиПоСтр. Однако с точки зрения качества кода и оптимизации этот вариант является плохой практикой (так называемым «костылем»).

Посмотрим, что произойдет в памяти компьютера при таком подходе:


// Система первый раз обращается к макету и создает область в памяти
ОбластьМакетаИтогиПоСтр = Макет.ПолучитьОбласть("ИтогиПоСтр"); 

// Система второй раз обращается к макету и создает точно такую же область в памяти
ИтогиПоСтр = Макет.ПолучитьОбласть("ИтогиПоСтр"); 

В результате мы получаем две абсолютно разные переменные, которые ссылаются на дублирующие друг друга объекты в оперативной памяти. Переменная ОбластьМакетаИтогиПоСтр при этом зависает в памяти неиспользованной, что снижает производительность системы и сильно запутывает любого другого разработчика, который будет читать ваш код в будущем.

Контекст использования кода: зачем нужен массив «СтрокаСПодвалом»?

Давайте разберем более глубокий практический вопрос: для чего в коде печатных форм 1С создается массив областей (в нашем случае СтрокаСПодвалом) и как он используется в дальнейшем?

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

Чтобы избежать этой проблемы, разработчики используют следующий алгоритм:

  1. Перед выводом очередной строки табличной части мы собираем в массив саму строку и все области подвала, которые обязаны идти следом (итоги по странице, подписи членов комиссии, расшифровки).
  2. Передаем этот массив в метод ПроверитьВывод() табличного документа.
  3. Метод ПроверитьВывод() имитирует печать данных областей с учетом установленного принтера, масштаба, полей и ориентации страницы.
  4. Если метод возвращает значение Ложь, это означает, что строка вместе с подвалом не помещается на текущем листе. В таком случае мы принудительно выводим разделитель страниц, печатаем шапку таблицы на новом листе и только после этого выводим строку.

Рассмотрим пример того, как это должно выглядеть в полноценном рабочем коде:


ТабДок = Новый ТабличныйДокумент;

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

Стандарты именования переменных в системе «1С:Предприятие»

В сообщениях форума автор темы задается вопросом: почему у одних областей есть приставка ОбластьМакета, а у других нет (например, ИтогоПоСтранице = Макет.ПолучитьОбласть("ИтогоПоСтранице"))?

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

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

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


ОбластьМакетаТитул          = Макет.ПолучитьОбласть("Титул");
ОбластьМакетаКомиссия        = Макет.ПолучитьОбласть("Комиссия");
ОбластьМакетаИтогоПоСтранице = Макет.ПолучитьОбласть("ИтогоПоСтранице");
ОбластьМакетаИтоги           = Макет.ПолучитьОбласть("Итоги");
ОбластьМакетаПодвал          = Макет.ПолучитьОбласть("Подвал");

Специфика регламентированной формы «Инвентаризационная опись 0504087»

В тексте обсуждаемой темы фигурирует макет "ИнвентаризационнаяОписьНФА_0504087_194н". Это унифицированная форма инвентаризационной описи нефинансовых активов, применяемая в государственных и бюджетных учреждениях РФ в соответствии с приказами Минфина (в частности, № 194н и № 52н).

Данная форма характеризуется крайне сложной структурой:

Из-за такой сложности типовые механизмы печати в конфигурации «1С:Бухгалтерия государственного учреждения» (БГУ) часто дорабатываются программистами под нужды конкретного ведомства. Выгрузка алгоритма во внешнюю печатную форму (ВПФ) — стандартный способ кастомизации без изменения типовой конфигурации. Корректная работа с областями макета и массивом проверки вывода в данном случае является критически важной, так как малейшая ошибка в расчете переноса строк приведет к тому, что многостраничная форма распечатается некорректно, нарушая строгие требования архивного делопроизводства госучреждений.

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

← На главную