Как перехватить выход из поля ввода в 1С, если значение не изменилось?

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

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

Почему не срабатывают события ПриИзменении и ОкончаниеВводаТекста

Выясним причину такого поведения платформы. В отличие от многих других сред разработки, в 1С:Предприятии концептуально отсутствует стандартное событие потери фокуса элементом (аналог onBlur или LostFocus). Архитектура платформы ориентирована на фиксацию изменений бизнес-данных, а не на детальный трекинг перемещения указателя мыши или курсора по элементам формы.

Рассмотрим подробнее два ключевых события элемента управления ПолеВвода:

  1. ОкончаниеВводаТекста — возникает в момент завершения интерактивного набора строки (например, при нажатии клавиши Enter или смене фокуса), но только в том случае, если редактируемый текст действительно отличался от исходного значения. Для ссылочных данных это событие отрабатывает до момента автоматического подбора объекта по строке.
  2. ПриИзменении — срабатывает после того, как новое значение окончательно зафиксировано в реквизите. Для ссылочных типов это происходит уже после выбора конкретной ссылки из базы.

Если в поле возникла ошибка, мы вернули фокус назад через установку свойства ЭтаФорма.ТекущийЭлемент, но пользователь не нажал ни одной клавиши внутри поля, внутренний буфер платформы считается немодифицированным. При повторной попытке перехода платформа видит, что значение не менялось, и просто переводит фокус на другой элемент, полностью игнорируя повторный вызов процедур ПриИзменении и ОкончаниеВводаТекста.

Способ 1. Имитация модификации текста через WScript.Shell

Посмотрим на обходной путь, предложенный непосредственно в обсуждении проблемы. Если платформа требует обязательного изменения текста для повторного вызова события, можно сымитировать нажатие клавиш операционной системы с помощью объекта WScript.Shell сразу после возврата фокуса в поле ввода.

Разберем по шагам логику этого решения:

  1. Проверяем введенное значение функцией валидации.
  2. Если обнаружена ошибка, выводим предупреждение и возвращаем фокус на элемент формы.
  3. Через метод SendKeys переводим каретку в конец строки, добавляем пробел и тут же удаляем его клавишей Backspace.

Shell = Новый COMОбъект("WScript.Shell"); 
Если НЕ ПроверитьСтрокуКомбинации(Комбинация1, ТекстОшибки) Тогда
    Предупреждение(ТекстОшибки);
    ЭтаФорма.ТекущийЭлемент = ЭлементыФормы.Комбинация1;
    Shell.SendKeys("{END}");
    Shell.SendKeys(" ");
    Shell.SendKeys("{BACKSPACE}");
    Возврат;
КонецЕсли;

В результате такой манипуляции итоговый текст в поле остается прежним, но флаг модификации внутреннего буфера взводится заново. При следующей попытке покинуть поле событие ПриИзменении гарантированно сработает повторно.

Важное ограничение метода: Использование WScript.Shell жестко привязывает решение к операционной системе Windows и может вызывать непредвиденные сбои, если в момент отправки нажатий пользователь переключит активное окно (нажатия клавиш могут уйти в стороннее приложение).

Способ 2. Контроль выхода через обработчик ПриВходе на целевых элементах

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

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

  1. Назначаем для всех соседних полей ввода и кнопок единую процедуру-обработчик события ПриВходе.
  2. При получении фокуса любым другим элементом проверяем корректность данных в обязательном поле.
  3. Если проверка не пройдена, информируем пользователя и принудительно возвращаем фокус назад.

Посмотрим на пример реализации модуля формы:


Процедура СоседнийЭлементПриВходе(Элемент)
    
    // Проверяем корректность критически важного поля
    Если НЕ ПроверитьКорректность(Комбинация1) Тогда
        Предупреждение("Поле 'Комбинация 1' заполнено некорректно! Завершите ввод.");
        ЭтаФорма.ТекущийЭлемент = ЭлементыФормы.Комбинация1;
    КонецЕсли;
    
КонецПроцедуры

Такой подход гарантирует, что пользователь не сможет продолжить работу с формой, нажать кнопку отправки или перейти к следующему полю, пока предыдущее заполнено с ошибками.

Способ 3. Поэтапная доступность полей ввода

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

Разберем по шагам, как организовать такую логику:

  1. При открытии формы делаем все поля ввода, кроме первого, недоступными: ЭлементыФормы.Комбинация2.Доступность = Ложь;.
  2. В обработчике ПриИзменении первого поля выполняем валидацию.
  3. Если значение корректно, разблокируем доступность следующего поля: ЭлементыФормы.Комбинация2.Доступность = Истина; и переводим на него фокус.
  4. Если значение некорректно, блокировка с последующих полей не снимается, а кнопка проведения или отправки остается неактивной.

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

Способ 4. Отслеживание фокуса через обработчик ожидания

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

Рассмотрим структуру данного подхода:


Перем ПредыдущийЭлемент;

Процедура ПриОткрытии()
    ПредыдущийЭлемент = ЭлементыФормы.Комбинация1;
    ПодключитьОбработчикОжидания("ПроверитьСменуФокуса", 1);
КонецПроцедуры

Процедура ПроверитьСменуФокуса()
    
    Текущий = ЭтаФорма.ТекущийЭлемент;
    
    Если ПредыдущийЭлемент = ЭлементыФормы.Комбинация1 И Текущий <> ЭлементыФормы.Комбинация1 Тогда
        Если НЕ ПроверитьКорректность(Комбинация1) Тогда
            Предупреждение("Исправьте значение в поле 'Комбинация 1'!");
            ЭтаФорма.ТекущийЭлемент = ЭлементыФормы.Комбинация1;
            Возврат;
        КонецЕсли;
    КонецЕсли;
    
    ПредыдущийЭлемент = Текущий;
    
КонецПроцедуры

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

← На главную