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

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

Разработка и поддержка прикладных решений на управляемой платформе 1С:Предприятие 8 уже давно стали стандартом. Тем не менее в эксплуатации остается огромное количество конфигураций на обычных формах (например, 1С:Управление производственным предприятием 1.3, 1С:Управление торговлей 10.3, 1С:Зарплата и управление персоналом 2.5). Работа в традиционном интерфейсе имеет свою специфику, и одна из наиболее частых проблем, с которой сталкиваются разработчики — это сохранение и автоматическое восстановление настроек форм, отборов и параметров ПостроителяОтчета.

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

---

Почему не работает флажок «При открытии» в обычных формах?

Начнем с анализа стандартного поведения платформы. В обычных формах при использовании типового механизма УниверсальныеМеханизмы (который интегрирован во все классические конфигурации) пользователь может сохранить текущие настройки формы и установить флажок «Использовать при открытии». Однако многие разработчики замечают, что при повторном запуске обработки параметры формы остаются пустыми.

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

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

---

Шаг 1. Программное восстановление настроек в обработчике «ПриОткрытии»

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

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


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

КонецПроцедуры

Использование конструкции УниверсальныеМеханизмы.ПолучитьНастройкуИспользоватьПриОткрытии() позволяет проверить, существует ли в системе запись для текущего пользователя с установленным признаком автоматического открытия. Если она найдена, структура заполняется данными, которые мы тут же раскладываем по реквизитам.

---

Шаг 2. Как правильно работать с ПостроителемОтчета и сохранять отборы

Довольно часто разработчики пытаются сохранить коллекцию отборов напрямую, используя вызовы вида ХранилищеНастроекДанныхФорм.Загрузить(..., "ПостроительОтчетаОтбор", ЭтотОбъект.ПостроительОтчета.Отбор). Это грубая ошибка.

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

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

  1. Через встроенный сериализатор платформы (НастройкиПостроителяОтчета): мы запрашиваем настройки построителя целиком с помощью метода ПолучитьНастройки(). На выходе получается объект типа НастройкиПостроителяОтчета. Именно его нужно сериализовать и сохранять в БД (например, упаковав в ХранилищеЗначения для записи в регистр).
  2. Использование локального кэша компьютера (быстродействующий вариант): если настройки нужно сохранять не в базе данных для совместного доступа, а локально для конкретного пользователя на его рабочем месте, можно использовать глобальные функции СохранитьЗначение() и ВосстановитьЗначение().

Посмотрим на пример локального сохранения и восстановления настроек:


Процедура ПередЗакрытием(Отказ, СтандартнаяОбработка)
    
    // Получаем текущие настройки построителя (включая все отборы, сортировки и группировки)
    НастройкиДляСохранения = ПостроительОтчета.ПолучитьНастройки();
    
    // Сохраняем во внутренний локальный кэш платформы под уникальным ключом
    СохранитьЗначение("МойОтчет_НастройкиПостроителя", НастройкиДляСохранения);
    
    // Сохраняем простые реквизиты формы
    СохранитьЗначение("МойОтчет_ДатаНачала", НачалоПериода);
    СохранитьЗначение("МойОтчет_ДатаКонца", КонецПериода);
    
КонецПроцедуры

Процедура ВосстановитьЛокальныеНастройки()
    
    // Восстанавливаем простые типы данных
    НачалоПериода = ВосстановитьЗначение("МойОтчет_ДатаНачала");
    КонецПериода  = ВосстановитьЗначение("МойОтчет_ДатаКонца");
    
    // Восстанавливаем сложные настройки построителя отчета
    НастройкиПостроителя = ВосстановитьЗначение("МойОтчет_НастройкиПостроителя");
    Если ТипЗнч(НастройкиПостроителя) = Тип("НастройкиПостроителяОтчета") Тогда
        // Применяем настройки обратно к построителю
        ПостроительОтчета.УстановитьНастройки(НастройкиПостроителя);
    КонецЕсли;
    
КонецПроцедуры

---

Шаг 3. Решение проблемы «Поле объекта не обнаружено АдресДоставки» при инициализации

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

Выясним причину этой ошибки: у объекта ПостроительОтчета есть коллекция доступных полей отбора (метод ПостроительОтчета.Отбор.ПолучитьДоступныеПоля()). Эта коллекция формируется платформой динамически на основе текста запроса, который передан в построитель, либо на основе источника данных. Если на момент вызова процедуры инициализации текст запроса в построителе еще не задан или построитель не выполнил метод заполнения настроек, коллекция доступных полей будет абсолютно пустой. Любое обращение к несуществующему свойству коллекции (например, ПоляОтбора.АдресДоставки) мгновенно вызовет аварийное завершение работы программы.

Чтобы избежать этой проблемы, необходимо строго соблюдать жизненный цикл инициализации объектов на форме. Посмотрим на правильный порядок действий:

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

Проанализируем правильную реализацию этого алгоритма в коде:


Процедура ИнициализироватьПостроительОтчета()
    
    // 1. Указываем текст запроса для построителя
    ПостроительОтчета.Текст = 
        "ВЫБРАТЬ
        |   Заказ.Ссылка КАК Ссылка,
        |   Заказ.Контрагент КАК Контрагент,
        |   Заказ.АдресДоставки КАК АдресДоставки,
        |   Заказ.Ответственный КАК Ответственный,
        |   Заказ.Утвержден КАК Утвержден
        |ИЗ
        |   Документ.ЗаказПокупателя КАК Заказ";
        
    // 2. Инициализируем структуру доступных полей на основе запроса
    ПостроительОтчета.ЗаполнитьНастройки();
    
КонецПроцедуры

Процедура УстановитьОтборыПоУмолчанию()
    
    // Получаем коллекцию доступных полей безопасным образом
    ДоступныеПоля = ПостроительОтчета.Отбор.ПолучитьДоступныеПоля();
    
    // Проверяем наличие поля "АдресДоставки" в доступных полях построителя
    ПолеАдрес = ДоступныеПоля.Найти("АдресДоставки");
    
    Если ПолеАдрес <> Неопределено Тогда
        // Только теперь мы можем безопасно менять представление или другие свойства поля
        ПолеАдрес.Представление = "Адрес доставки покупателя";
        
        // Проверяем, добавлен ли уже этот элемент в текущие отборы формы
        ЭлементОтбора = ПостроительОтчета.Отбор.Найти("АдресДоставки");
        Если ЭлементОтбора = Неопределено Тогда
            // Если отбора нет, создаем его и настраиваем дефолтное состояние
            НовыйОтбор = ПостроительОтчета.Отбор.Добавить("АдресДоставки");
            НовыйОтбор.Использование = Ложь; // По умолчанию отбор выключен, но виден пользователю
        КонецЕсли;
    КонецЕсли;
    
    // Аналогично и безопасно настраиваем отбор "Утвержден"
    ПолеУтвержден = ДоступныеПоля.Найти("Утвержден");
    Если ПолеУтвержден <> Неопределено Тогда
        ЭлементУтвержден = ПостроительОтчета.Отбор.Найти("Утвержден");
        Если ЭлементУтвержден = Неопределено Тогда
            НовыйОтбор = ПостроительОтчета.Отбор.Добавить("Утвержден");
            НовыйОтбор.ВидСравнения = ВидСравнения.Равно;
            НовыйОтбор.Значение = Ложь;
            НовыйОтбор.Использование = Истина; // Этот отбор по умолчанию активен
        КонецЕсли;
    КонецЕсли;

КонецПроцедуры

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

---

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

Для стабильной работы механизмов сохранения параметров в обычных формах 1С придерживайтесь следующих правил:

← На главную