Как задать вопрос пользователю сразу после открытия формы в 1С:Предприятии 8

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

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

В этой статье мы подробно разберем, как решить эту задачу правильно и красиво как для классических обычных форм (толстый клиент, например, в УТ 10.2, УПП 1.3), так и для современных управляемых форм (тонкий и веб-клиент, интерфейс «Такси»), полностью отказавшись от устаревшей и небезопасной синхронной модальности.

Метод №1. Использование обработчика ожидания (универсальный способ)

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

Рассмотрим по шагам реализацию этого механизма для обычных форм:

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

Посмотрим на пример программного кода для обычного приложения:


Процедура ПриОткрытии()
    // Подключаем однократный обработчик ожидания на 0.1 секунды.
    // Третий параметр "Истина" указывает платформе, что вызов должен быть однократным.
    ПодключитьОбработчикОжидания("ЗадатьВопросПослеОткрытия", 0.1, Истина);
КонецПроцедуры

Процедура ЗадатьВопросПослеОткрытия() Экспорт
    // На всякий случай принудительно отключаем обработчик в первой строке
    ОтключитьОбработчикОжидания("ЗадатьВопросПослеОткрытия");
    
    // Вызываем стандартный диалог вопроса
    Кнопки = РежимДиалогаВопрос.ДаНет;
    Ответ = Вопрос("Желаете автоматически заполнить документ данными по умолчанию?", Кнопки, 0);
    
    Если Ответ = КодВозвратаДиалога.Да Тогда
        // Здесь мы пишем код заполнения реквизитов документа
    КонецЕсли;
КонецПроцедуры

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

Метод №2. Альтернативный обходной путь для обычных форм через ОбновлениеОтображения

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

Поскольку событие ОбновлениеОтображения() срабатывает регулярно при любых изменениях на форме, нам необходимо гарантировать, что вопрос будет задан ровно один раз при первом запуске. Для этого мы применим флаг-переменную на уровне модуля формы.

Давайте проанализируем этот программный код:


Перем ФормаУжеОткрыта; // Переменная модуля для хранения состояния формы

Процедура ПриОткрытии()
    // Инициализируем флаг при открытии формы
    ФормаУжеОткрыта = Ложь;
КонецПроцедуры

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

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

Метод №3. Реализация в управляемых формах (отказ от модальности)

В современных конфигурациях 1С (ERP, УТ 11, БП 3.0, ЗУП 3 и др.) свойство конфигурации «Режим использования модальности» по умолчанию выставлено в значение «Не использовать». Это требование продиктовано кроссплатформенностью: веб-клиенты в браузерах физически не поддерживают классические модальные окна, блокирующие поток выполнения кода.

Если вы попытаетесь вызвать метод Вопрос() в управляемом приложении, система аварийно завершит работу с ошибкой. В управляемом интерфейсе все взаимодействия строятся по асинхронной схеме с использованием процедур обратного вызова (оповещений).

Для реализации нашей задачи в управляемой форме выполним следующие шаги:

  1. В обработчике ПриОткрытии() на клиенте подключаем однократный обработчик ожидания.
  2. В процедуре обработчика ожидания создаем объект ОписаниеОповещения, указывающий на метод, который обработает выбор пользователя.
  3. Вызываем немодальную функцию ПоказатьВопрос().

Рассмотрим пример правильного кода для управляемого приложения:


&НаКлиенте
Процедура ПриОткрытии(Отказ)
    // Подключаем однократный таймер на клиенте
    ПодключитьОбработчикОжидания("ПослеОткрытияФормы", 0.1, Истина);
КонецПроцедуры

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

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

Метод №4. Открытие сложной формы вопроса с блокировкой интерфейса

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

В управляемом режиме для этого применяется правильное использование параметра РежимОткрытияОкна при вызове метода ОткрытьФорму(). Мы можем настроить блокировку интерфейса без использования устаревших модальных окон.

Для блокировки предусмотрены следующие параметры системного перечисления РежимОткрытияОкнаФормы:

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


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

&НаКлиенте
Процедура ПослеЗакрытияФормыВопроса(РезультатЗакрытия, ДополнительныеПараметры) Экспорт
    Если РезультатЗакрытия <> Неопределено Тогда
        // Обрабатываем полученные из вспомогательной формы параметры
        ПрименитьПараметрыКДокументу(РезультатЗакрытия);
    КонецЕсли;
КонецПроцедуры

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

← На главную