Как зациклить вывод предупреждения в 1С, пока не будет получен верный ответ

Программист IT и автоматизация бизнеса
← На главную

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

Анализ проблемы автоматического закрытия окон

Разберем типичную ситуацию: программист использует стандартную функцию Вопрос(). Если в параметрах указана кнопка по умолчанию (например, "ОК" или "Да"), то любой лишний Enter приведет к выполнению действия, которое, возможно, следовало бы предотвратить. Если же кнопкой по умолчанию назначить "Нет", то окно просто закроется, и действие не выполнится, но пользователь так и не поймет, что именно пошло не так. Наша задача — создать цикл, который будет «выбрасывать» вопрос снова и снова, пока не будет нажата конкретная кнопка (например, "Да"), требующая от пользователя переключения внимания со сканера на мышь или клавиатуру.

Решение для модального режима (устаревший подход)

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


Ответ = КодВозвратаДиалога.Нет;
Пока Ответ <> КодВозвратаДиалога.Да Цикл
    Ответ = Вопрос("Вы действительно проверили товар вручную?", РежимДиалогаВопрос.ДаНет,, КодВозвратаДиалога.Нет, "Внимание!");
    Если Ответ = КодВозвратаДиалога.Нет Тогда
        // Можно добавить дополнительное предупреждение или паузу
    КонецЕсли;
КонецЦикла;

В данном примере, если пользователь нажимает Enter, срабатывает кнопка по умолчанию ("Нет"), и цикл заходит на следующую итерацию, снова открывая окно. Выйти из цикла можно только осознанным выбором варианта "Да".

Решение для современных конфигураций (Асинхронный подход)

В современных версиях платформы 8.3 (особенно в Управляемых формах) использование модальных окон запрещено. Программа не останавливается на строке вызова вопроса, а идет дальше. Для реализации циклического вопроса здесь необходимо использовать механизм ОписанияОповещения. Разберем по шагам, как это реализовать.

Сначала создадим процедуру, которая инициирует показ вопроса:


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

Теперь реализуем процедуру ПослеПоказаВопроса, которая будет анализировать результат нажатия и, если нужно, вызывать вопрос повторно:


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

Особенности реализации для Обычных форм

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

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

Борьба с автоматизмом сканера (UX советы)

Проанализируем ситуацию со сканером более глубоко. Если сканер посылает Enter очень быстро, пользователь может даже не заметить мерцания окна. Чтобы гарантированно прервать этот поток, можно применить следующие хитрости:

1. Использование тайм-аута. В методе ПоказатьВопрос есть параметр "Таймаут". Если установить его, окно закроется само через указанное время. Однако в нашем случае лучше использовать обратную логику: программно блокировать возможность ответа в первую секунду появления окна.

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

3. Проверка «Крестика». Как отмечено в обсуждении, пользователь может попытаться закрыть окно на «крестик». В асинхронном методе переменная Результат в этом случае примет значение Неопределено. Обязательно обрабатывайте этот вариант, чтобы окно нельзя было просто «скинуть»:


Если Результат <> КодВозвратаДиалога.Да Тогда
    ПоказатьВопросЦиклично(); // Не даем закрыть, пока не нажмут "Да"
КонецЕсли;

Заключение

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

← На главную