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