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