Как вернуть и удержать фокус на реквизите формы в 1С при работе со считывателем карт?

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

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

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

Проанализируем проблему: почему ломается фокус ввода?

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

Ранее логика работы программы выглядела следующим образом:

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

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

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


Способ 1. Быстрый и надежный вариант: Использование обработчика ожидания

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

Разберем по шагам, как это реализовать в коде модуля формы:

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


Процедура УстановитьФокусНаКарту() Экспорт
    // Возвращаем фокус на поле ввода карты
    ЭтаФорма.ТекущийЭлемент = ЭлементыФормы.Карта;
КонецПроцедуры

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


Процедура КартаПриИзменении(Элемент)
    
    // ... Ваш код обработки данных карты (поиск сотрудника, запись события) ...
    
    // Подключаем однократный обработчик ожидания (параметр "Однократно" = Истина)
    ПодключитьОбработчикОжидания("УстановитьФокусНаКарту", 0.1, Истина);
    
КонецПроцедуры

Использование этого метода позволяет гарантированно "вернуть" фокус в поле Карта сразу после того, как платформа попытается увести его на другой элемент.


Способ 2. Борьба со сбросом фокуса при выводе предупреждений (Асинхронность)

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

Рассмотрим, как правильно организовать вывод предупреждения и последующий возврат фокуса:


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

Процедура ПослеЗакрытияПредупрежденияОбОшибке(ДополнительныеПараметры) Экспорт
    // Очищаем неверно считанное значение, чтобы поле было готово к новому вводу
    ЭлементыФормы.Карта.Значение = "";
    // Возвращаем фокус на поле ввода после того, как пользователь закрыл предупреждение
    ПодключитьОбработчикОжидания("УстановитьФокусНаКарту", 0.1, Истина);
КонецПроцедуры

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


Способ 3. Ограничение обхода элементов (Настройка свойств формы)

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

Рассмотрим этот вариант настройки:

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


Способ 4. Архитектурно правильное решение: Переход на внешние события

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

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

При таком подключении интеграция с 1С выглядит следующим образом:

  1. В операционную систему устанавливается драйвер оборудования (например, стандартный драйвер "1С:Сканер штрихкодов" или внешняя компонента от производителя).
  2. В конфигурации настраивается подключение торгового оборудования.
  3. В модуле формы перехватывается предопределенное системное событие ВнешнееСобытие.

Посмотрим на пример кода, реализующий обработку данных в форме при правильном подключении оборудования:


Процедура ВнешнееСобытие(Источник, Событие, Данные)
    
    // Проверяем, что событие пришло от нашего подключенного считывателя карт
    Если ПолучитьСобытиеОтСчитывателя(Источник, Событие) Тогда
        
        // Получаем код карты напрямую из порта устройства
        КодКарты = СокрЛП(Данные);
        
        // Обрабатываем полученные данные
        ОбработатьСчитаннуюКарту(КодКарты);
        
    КонецЕсли;
    
КонецПроцедуры

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


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

Выбор конкретного решения зависит от ваших ресурсов и задач:

← На главную