Как обрабатывать события сканера штрихкодов только на активной форме в 1С:Предприятие (УФ)?

Программист 1С v8.3 (Управляемые формы) Торговля и дистрибуция
← На главную

Мы, разработчики 1С, часто сталкиваемся с задачами автоматизации, особенно при работе с внешним оборудованием, таким как сканеры штрихкодов, подключенные к терминалам сбора данных (ТСД) или стационарным рабочим местам. Одна из распространенных проблем возникает, когда событие сканирования штрихкода, инициированное методом Оповестить() из модуля приложения или обработчика внешнего события, обрабатывается процедурой ОбработкаОповещения сразу на всех открытых управляемых формах. Это может приводить к нежелательным действиям, конфликтам в логике и ошибкам в работе приложения, поскольку каждая форма пытается отреагировать на одно и то же событие.

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

Выясняем причину: Почему событие срабатывает на всех формах?

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

Решение 1: Использование метода ЭтаФорма.ВводДоступен() для фильтрации событий

Это наиболее прямолинейное, эффективное и часто используемое решение для нашей задачи. Метод ЭтаФорма.ВводДоступен() позволяет нам определить, является ли текущая форма активной и доступна ли для ввода данных пользователем в данный момент.

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

Решение 2: Дифференциация событий через параметр ИмяСобытия

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

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

Решение 3: Архитектурный подход – Управление жизненным циклом форм

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

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

Решение 4: Глобальная обработка оповещений и Библиотека Подключаемого Оборудования (БПО)

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

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

Подводим итоги

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

  1. Самым простым и эффективным способом для большинства случаев является использование метода ЭтаФорма.ВводДоступен() внутри процедуры ОбработкаОповещения каждой формы. Это обеспечивает локальную фильтрацию событий.
  2. Если у вас есть возможность управлять вызовом Оповестить(), используйте **параметр ИмяСобытия** для контекстной обработки. Это позволяет передавать дополнительный смысл событию.
  3. Для поддержания порядка, упрощения логики и улучшения пользовательского опыта, рассмотрите **архитектурный подход** с одной активной формой на каждом шаге процесса. Это уменьшает сложность и потенциальные конфликты.
  4. В более сложных сценариях с Библиотекой Подключаемого Оборудования (БПО) или централизованной обработкой можно реализовать **глобальную "служебную" форму или общий модуль** для перехвата и маршрутизации событий.

Мы рекомендуем начать с метода ЭтаФорма.ВводДоступен() как с наиболее прямого и легко реализуемого решения, а затем при необходимости расширять логику с учетом других представленных методов для построения более надежной и гибкой системы обработки внешних событий.

← На главную