При разработке функционала для работы с торговым оборудованием в конфигурациях на обычных формах (например, УТ 10.3) разработчики часто сталкиваются с ситуацией, когда данные со сканера штрихкода обрабатываются не в той форме, которая активна в данный момент, или не обрабатываются вовсе. Центральную роль в этой логике играет метод ВводДоступен(). Рассмотрим подробно, как работает этот механизм, почему он может давать сбои в режиме отладки или терминального доступа, и как правильно спроектировать архитектуру приложения для стабильной работы со сканером.
Разберем, как устроена подсистема торгового оборудования в типовых решениях. Когда мы вызываем метод ПолучитьСерверТО().ПодключитьКлиента(ЭтаФорма), мы фактически регистрируем текущую форму в глобальном массиве слушателей событий. Это означает, что при срабатывании сканера платформа 1С разошлет оповещение ВнешнееСобытие() во все формы, которые были подключены этим методом и еще не закрыты. Для настройки интеграции оборудования через этот механизм можно использовать обработку обслуживания сканеров через драйвер NativeAPI.
Проанализируем типовой код обработки события в форме:
Процедура ВнешнееСобытие(Источник, Событие, Данные)
Если Не ВводДоступен() Тогда
Возврат;
КонецЕсли;
ПолучитьСерверТО.ОбработатьВнешнееСобытие(Источник, Событие, Данные, ЭтаФорма);
КонецПроцедуры
Здесь проверка Если Не ВводДоступен() Тогда Возврат; служит фильтром. Поскольку событие прилетает во все открытые формы (и в основную, и в модальную произвольную), эта строка должна отсекать неактивные окна, чтобы штрихкод обработало только то окно, с которым сейчас работает пользователь.
Выясним причину, по которой программисты часто получают неверные результаты при тестировании. Если вы установите точку останова на строке с вызовом ВводДоступен(), то при активации сканера фокус системы переключится с окна 1С:Предприятие на окно Конфигуратора (в отладчик). В этот момент для платформы интерактивный ввод в форму становится недоступен, и метод закономерно возвращает Ложь.
Важный вывод: для корректной проверки работы фокуса нельзя использовать точки останова непосредственно на проверке. Вместо этого рекомендуется использовать Сообщить() или запись в журнал регистрации для мониторинга состояния метода в реальном времени без прерывания работы интерфейса.
Рассмотрим ситуацию, когда в терминальной сессии метод ВводДоступен() всегда возвращает Ложь, даже если форма визуально активна. Это происходит из-за специфики передачи фокуса между локальной машиной и удаленным рабочим столом. Если пользователь переключился на другое приложение на своем локальном компьютере (например, в браузер или почту), то внутри терминальной сессии 1С окно теряет статус активного для ввода, хотя оно и не перекрыто другими окнами 1С.
Также стоит учитывать задержки передачи данных. В условиях Citrix событие от COM-объекта (драйвера сканера) может прийти быстрее, чем Windows успеет обновить статус фокуса окна после того, как пользователь кликнул по нему. В таких случаях данные "проглатываются" из-за срабатывания оператора Возврат.
Проанализируем ситуацию из практики: открыта основная форма, из нее модально открывается произвольная форма (например, форма авторизации или выбора характеристик). Если в обеих формах вызван метод ПодключитьКлиента(ЭтаФорма), возникают следующие риски:
ВводДоступен() в ней всегда будет Ложь. Это правильно.ПолучитьСерверТО().ОтключитьКлиента(ЭтаФорма), ссылка на эту форму остается в массиве подключенных клиентов. При следующем сканировании платформа попытается вызвать ВнешнееСобытие в уже закрытой (но не удаленной из памяти) форме. Это приводит к непредсказуемым ошибкам и множественному открытию новых окон.Если стандартный механизм с ВводДоступен() работает нестабильно, рассмотрим более надежные способы организации работы:
Вместо того чтобы подписывать каждую форму на торговое оборудование, можно реализовать схему "Диспетчера":
ВнешнееСобытие этой формы вызываем Оповестить("СканированиеШтрихкода", ДанныеШК);.ОбработкаОповещения(ИмяСобытия, Параметр, Источник).Этот метод хорош тем, что ОбработкаОповещения работает более предсказуемо в иерархии окон, и вы сами можете управлять тем, какая форма должна реагировать на сообщение.
В новых версиях платформы 8.3 для более точного определения активности окна можно попробовать проанализировать статус окна через коллекцию окон приложения. Это более трудоемкий путь, требующий использования методов ЭтаФорма.ТекущееОкно().Активно(), но он дает более точный результат, чем ВводДоступен(), который слишком чувствителен к системному фокусу ОС.
Если данные сканера критически важны и не должны теряться при свернутом окне, можно отказаться от Возврат в случае Не ВводДоступен(). Вместо этого сохраняйте данные в глобальную переменную (в модуле приложения или параметре сеанса). При активации формы (событие ПриАктивизации или через обработчик ожидания) проверяйте наличие данных в этом буфере и обрабатывайте их.
Для стабильной работы в УТ 10.3 придерживайтесь следующих правил:
ОтключитьКлиента(ЭтаФорма) в процедуре ПриЗакрытии().ВводДоступен(), помните, что он вернет Ложь, если поверх формы открыто любое другое окно (даже системное предупреждение).ЖурналРегистрации, чтобы не перехватывать фокус окном конфигуратора.Соблюдение этих принципов позволит избежать "фантомных" срабатываний и обеспечит надежный ввод данных даже в сложных многооконных интерфейсах на базе обычных форм.