Мы, разработчики 1С, часто сталкиваемся с задачами автоматизации, особенно при работе с внешним оборудованием, таким как сканеры штрихкодов, подключенные к терминалам сбора данных (ТСД) или стационарным рабочим местам. Одна из распространенных проблем возникает, когда событие сканирования штрихкода, инициированное методом Оповестить() из модуля приложения или обработчика внешнего события, обрабатывается процедурой ОбработкаОповещения сразу на всех открытых управляемых формах. Это может приводить к нежелательным действиям, конфликтам в логике и ошибкам в работе приложения, поскольку каждая форма пытается отреагировать на одно и то же событие.
Давайте вместе разберем эту ситуацию и рассмотрим наиболее эффективные способы организации обработки событий сканирования таким образом, чтобы действия выполнялись строго на той форме, которая активна в данный момент, или согласно четко определенной логике.
При использовании метода Оповестить() из глобального контекста (например, из модуля приложения, общего модуля или в ответ на внешнее событие), система 1С:Предприятие по своей внутренней архитектуре рассылает это оповещение всем открытым управляемым формам, у которых определена процедура ОбработкаОповещения. Это стандартное поведение платформы, и оно полезно во многих сценариях, требующих глобальной реакции. Однако в нашем случае, когда необходимо строго контекстное выполнение (только на активной форме), такое поведение становится источником проблемы.
ЭтаФорма.ВводДоступен() для фильтрации событийЭто наиболее прямолинейное, эффективное и часто используемое решение для нашей задачи. Метод ЭтаФорма.ВводДоступен() позволяет нам определить, является ли текущая форма активной и доступна ли для ввода данных пользователем в данный момент.
ОбработкаОповещения, где требуется обработка событий сканирования. Это позволяет каждой форме самостоятельно решать, реагировать ли на оповещение.ОбработкаОповещения следующим образом:
&НаКлиенте
Процедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник)
// В первую очередь проверяем, активна ли текущая форма.
// Если форма не активна, мы сразу же прекращаем обработку события для этой формы.
Если НЕ ЭтаФорма.ВводДоступен() Тогда
Возврат; // Форма неактивна, игнорируем событие
КонецЕсли;
// Далее располагается основная логика обработки события
// Проверяем, что это именно то событие, которое мы ожидаем от сканера
Если ИмяСобытия = "СканШтрихкода" Тогда
Штрихкод = Параметр; // Параметр обычно содержит отсканированный штрихкод
// Выводим информацию для отладки или пользователя
Сообщить("Штрихкод '" + Штрихкод + "' отсканирован на активной форме " + ЭтаФорма.Заголовок);
// Выполняем действия, специфичные для этой конкретной формы.
// Например, поиск товара, добавление в документ, изменение состояния интерфейса и т.д.
// ... Ваша логика обработки ...
КонецЕсли;
КонецПроцедуры
ЭтаФорма.ВводДоступен() вернет значение Ложь. В этом случае мы сразу же завершаем выполнение процедуры ОбработкаОповещения для данной формы, предотвращая тем самым выполнение нежелательных действий на неактивных формах.ЭтаФорма.ВводДоступен() **может всегда возвращать Ложь**, даже если форма была активна до момента срабатывания точки останова. Для корректной проверки поведения необходимо запускать тестирование без активного отладчика или ставить точки останова после проверки на ВводДоступен(), чтобы увидеть, какой результат возвращается в рабочем режиме.ИмяСобытияХотя автор исходной темы предполагал, что имя события сканирования штрихкода всегда будет одним и тем же, существуют сценарии, когда мы можем контролировать или модифицировать это имя. Этот подход требует большей управляемости над источником вызова Оповестить().
Оповестить(), например, из какого-либо промежуточного обработчика внешнего события, из общего модуля или специальной служебной формы, мы можем передавать различные значения в параметре ИмяСобытия. Это позволяет нам передавать контекст события.Оповестить("СканДокумента", Штрихкод);.Оповестить("СканТовараВПодборе", Штрихкод);.ОбработкаОповещения конкретных форм мы тогда явно проверяем это имя события и выполняем соответствующие действия:
&НаКлиенте
Процедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник)
// Дополнительно можно добавить проверку ЭтаФорма.ВводДоступен() для надежности
Если НЕ ЭтаФорма.ВводДоступен() Тогда
Возврат;
КонецЕсли;
Если ИмяСобытия = "СканДокумента" Тогда
Штрихкод = Параметр;
Сообщить("Форма документа: отсканирован штрихкод " + Штрихкод);
// Логика для формы документа: поиск документа по штрихкоду
ИначеЕсли ИмяСобытия = "СканТовараВПодборе" Тогда
Штрихкод = Параметр;
Сообщить("Форма подбора: отсканирован штрихкод товара " + Штрихкод);
// Логика для формы подбора товаров: поиск товара и добавление в список
КонецЕсли;
КонецПроцедуры
Оповестить(). Однако, если событие генерируется напрямую драйвером сканера, работающим, например, через эмуляцию клавиатуры, или через обработку внешнего события, управляемую платформой без возможности указания произвольного имени, то параметр ИмяСобытия может быть фиксированным или вообще отсутствовать в том виде, в каком нам нужно. В таких случаях метод ВводДоступен() остается более универсальным и независимым от источника события решением.Один из наиболее чистых архитектурных подходов, предложенный в обсуждении, заключается в том, чтобы **в один момент времени иметь только одну открытую форму, которая соответствует текущему шагу бизнес-процесса**. Это не столько техническое решение на уровне кода, сколько методология построения пользовательского интерфейса и логики.
ОповеститьОВыборе(). Этот метод позволяет вернуть выбранные или обработанные данные в вызывающую форму после того, как текущая форма будет закрыта.
// В форме-источнике после выполнения действий и перед закрытием
// Например, после выбора документа
ОповеститьОВыборе(ВыбранныйДокумент);
Закрыть();
// В форме-приемнике (которая вызвала форму-источник)
Процедура ОбработкаВыбора(ВыбранныйОбъект, Источник)
Если ТипЗнч(ВыбранныйОбъект) = Тип("ДокументСсылка.МойДокумент") Тогда
МойДокумент = ВыбранныйОбъект;
// Продолжаем работу с выбранным документом
Сообщить("Выбран документ: " + МойДокумент);
КонецЕсли;
КонецПроцедуры
Для более сложной и универсальной работы со сканерами штрихкодов, особенно в типовых конфигурациях 1С, часто используется Библиотека Подключаемого Оборудования (БПО). Этот подход позволяет централизовать обработку событий и маршрутизировать их.
Оповестить() из общего модуля.ВводДоступен() **всегда будет возвращать Ложь**, так как она никогда не является активной для пользователя. Поэтому ее нельзя использовать для определения активности.ВводДоступен() для *других* форм), и затем уже **целенаправленно отправить оповещение** только этой активной форме, используя Оповестить() с определенным ИмяСобытия и Параметр.
// В модуле приложения или общем модуле, если сканер подключен глобально
Процедура ОбработкаВнешнегоСобытия(Источник, Событие, Данные)
Если Источник = "ПодключаемоеОборудование" И Событие = "ScanData" Тогда
// Здесь 'Данные' будет содержать отсканированный штрихкод
Штрихкод = Данные;
// Теперь нам нужно определить активную форму и отправить ей оповещение.
// Это можно сделать, например, через итерацию по всем открытым формам
// или через вызов метода глобальной обработки, который уже сам определит,
// какая форма должна обработать этот штрихкод.
// Для примера, оповещаем все формы с новым, более специфичным именем события
Оповестить("ОтсканированШтрихкодИзБПО", Штрихкод);
КонецЕсли;
КонецПроцедуры
ОбработкаОповещения, где она уже проверит ИмяСобытия = "ОтсканированШтрихкодИзБПО" и, крайне желательно, дополнительно ЭтаФорма.ВводДоступен().Мы рассмотрели несколько подходов к решению проблемы обработки событий сканера штрихкодов только на активной форме в 1С:Предприятие (Управляемые формы). Выбор конкретного подхода зависит от вашей текущей архитектуры, требований к гибкости и особенностей используемого оборудования.
ЭтаФорма.ВводДоступен() внутри процедуры ОбработкаОповещения каждой формы. Это обеспечивает локальную фильтрацию событий.Оповестить(), используйте **параметр ИмяСобытия** для контекстной обработки. Это позволяет передавать дополнительный смысл событию.Мы рекомендуем начать с метода ЭтаФорма.ВводДоступен() как с наиболее прямого и легко реализуемого решения, а затем при необходимости расширять логику с учетом других представленных методов для построения более надежной и гибкой системы обработки внешних событий.