Как отключить автоматический переход фокуса между элементами формы по нажатию Enter в 1С:Предприятии 8.3?

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

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

В этой статье мы подробно рассмотрим, почему возникают трудности с управлением фокусом по Enter в управляемых формах 1С, проанализируем различные подходы к решению этой проблемы и предоставим рабочие примеры кода как для управляемых, так и для обычных форм.

Почему прямой возврат фокуса не всегда работает?

Многие разработчики интуитивно пытаются вернуть фокус на текущее поле внутри обработчиков событий, таких как ПриИзменении, ОбработкаВыбора или ОкончаниеВводаТекста, используя конструкцию ЭтаФорма.ТекущийЭлемент = Элементы.ИмяНужногоЭлементаФормы. Однако, как показывает практика и пояснения от службы поддержки 1С, этот подход часто оказывается неэффективным, особенно в управляемых формах и в более новых версиях платформы.

Давайте выясним причину такого поведения. Когда мы нажимаем Enter, платформа выполняет несколько действий:

  1. Фиксирует введенное значение в текущем поле.
  2. Инициирует вызов соответствующих событий (например, ПриИзменении).
  3. До вызова этих обработчиков или сразу после их завершения платформа уже принимает решение о переходе фокуса на следующий элемент в порядке обхода.

Это означает, что наша программная установка ЭтаФорма.ТекущийЭлемент = Элементы.ИмяНужногоЭлементаФормы внутри обработчика выполняется, но затем платформа тут же "перебивает" наш выбор, возвращая фокус на элемент, который она определила как следующий. В результате, несмотря на наш код, курсор все равно "прыгает" на соседнее поле.

Рассмотрим, как эту проблему можно эффективно решить.

Метод 1: Использование обработчика ожидания (наиболее надежный для управляемых форм)

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

Принцип работы

Мы используем событие поля ввода, например, ОкончаниеВводаТекста или ПриИзменении. Внутри этого события мы не пытаемся вернуть фокус немедленно, а подключаем обработчик ожидания, который через очень короткий промежуток времени (например, 0.1 секунды) выполнит команду по установке фокуса на нужное нам поле.

Давайте посмотрим на пример кода:


&НаКлиенте
Процедура ПолеВводаШК_ОкончаниеВводаТекста(Элемент, Текст, ДанныеВыбора, Параметры, СтандартнаяОбработка)
    // Здесь мы можем обработать введенные данные, например, найти товар по штрихкоду
    // ...

    // Отключаем стандартную обработку, если это необходимо,
    // но в данном случае для возврата фокуса это не критично
    // СтандартнаяОбработка = Ложь; 

    // Подключаем обработчик ожидания для возврата курсора
    ПодключитьОбработчикОжидания("ВернутьКурсорНаПолеВводаШК", 0.1, Истина); 
КонецПроцедуры

&НаКлиенте
Процедура ВернутьКурсорНаПолеВводаШК()
    // Перед возвратом фокуса, если нужно, очистим поле для нового ввода
    ШК = ""; // Предполагается, что "ШК" - это реквизит формы, связанный с полем ввода
    
    // Возвращаем фокус на наше поле ввода
    ЭтаФорма.ТекущийЭлемент = Элементы.ПолеВводаШК;
КонецПроцедуры

Разберем этот подход по шагам:

  1. ПолеВводаШК_ОкончаниеВводаТекста(Элемент, Текст, ...): Это обработчик события поля ввода, который срабатывает после того, как пользователь завершил ввод текста (например, нажал Enter). Здесь мы выполняем всю необходимую логику обработки данных.
  2. ПодключитьОбработчикОжидания("ВернутьКурсорНаПолеВводаШК", 0.1, Истина):
    • Первый параметр – имя процедуры, которую необходимо выполнить.
    • Второй параметр – интервал в секундах (0.1 секунды – обычно достаточно для управляемых форм, чтобы платформа успела обработать свои очереди событий).
    • Третий параметр – Истина означает, что обработчик будет выполнен только один раз, после чего автоматически отключится.
  3. ВернутьКурсорНаПолеВводаШК(): Это отдельная клиентская процедура, которая будет вызвана обработчиком ожидания. В ней мы выполняем два ключевых действия:
    • ШК = "": Очищаем значение поля, если предполагается повторный ввод. Это важно для сценариев, таких как сканирование множества штрихкодов.
    • ЭтаФорма.ТекущийЭлемент = Элементы.ПолеВводаШК: Устанавливаем фокус обратно на наше поле ввода. Поскольку эта команда выполняется асинхронно, через небольшой промежуток времени, она гарантированно "перебивает" стандартное поведение платформы по переходу фокуса.

Этот метод доказал свою работоспособность в различных версиях платформы 8.3, включая те, где прямая установка фокуса перестала работать (например, при переходе с 8.3.8.2322 на 8.3.14.x или 8.3.15.x в определенных сценариях).

Нюансы для Web-клиента

Если ваша база используется через Web-клиент, поведение фокуса может быть еще более непредсказуемым из-за особенностей работы браузеров. В этом случае, метод с ПодключитьОбработчикОжидания становится практически единственным стабильным решением. Браузеры обрабатывают события асинхронно, и попытка мгновенно вернуть фокус в обработчике ПриИзменении может быть проигнорирована или отменена внутренними скриптами платформы, которые уже запустили процесс перехода на следующий HTML-элемент <input>.

Метод 2: Свойство формы «Поведение клавиши Enter»

Для управляемых форм существует свойство самой формы «Поведение клавиши Enter». Мы можем установить его в значение «Кнопка по умолчанию».

Принцип работы

Если мы установим это свойство, но при этом не назначим ни одной кнопке формы роль «Кнопка по умолчанию», то при нажатии Enter платформа перестанет автоматически переводить фокус на следующий элемент. Вместо этого, она будет искать кнопку по умолчанию, но так как её нет, стандартное поведение обхода элементов по Enter будет подавлено. Фокус может остаться на текущем элементе или вести себя непредсказуемо (например, оставаться в пределах текущего элемента, но не реагировать на повторные Enter как на событие поля).

Преимущества и ограничения

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

  1. Отсутствие "Кнопки по умолчанию": Если нам нужна функциональность "Кнопки по умолчанию" (например, нажатие на "ОК" при Enter), этот метод не подойдет.
  2. Побочные эффекты: В некоторых случаях Enter может перестать реагировать на любые действия, кроме переноса строки в многострочном поле.
  3. Не всегда гарантировано: Поведение может отличаться в зависимости от версии платформы и конфигурации формы. Некоторые пользователи отмечали, что этот метод помог им, другие — что он не дал ожидаемого результата.

Мы рекомендуем использовать этот метод только после тестирования и если он не создает неудобств в других частях формы.

Метод 3: Установка «Многострочного режима» для поля ввода

Если наше поле ввода предназначено для текста, мы можем установить для него свойство «Многострочный режим» в значение «Да».

Принцип работы

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

Преимущества и ограничения

  1. Простота: Требует лишь изменения одного свойства поля.
  2. Визуальный аспект: Если нам не нужны переносы строк, и поле должно выглядеть как однострочное, этот метод может быть не идеален. Мы можем попытаться программно перехватывать ввод и удалять символы переноса строки, но это усложнит код.
  3. Специфичность: Подходит только для текстовых полей, где функциональность переноса строки (или её отсутствие) может быть принята. Для полей с численным вводом или выбором из списка это неприменимо.

Метод 4: Решение для обычных форм (через событие «ОбновлениеОтображения»)

Хотя основная проблема обсуждается в контексте управляемых форм, пользователи сталкиваются с похожими сложностями и в обычных формах, особенно в новых версиях платформы, где поведение фокуса могло измениться. Для обычных форм предложено следующее решение:

Принцип работы

Мы используем событие формы ОбновлениеОтображения. Это событие срабатывает при каждом обновлении отображения формы. В нем мы проверяем, нужно ли установить фокус на определенный элемент, и если да, то выполняем эту установку.

Давайте разберем пример:


// В модуле формы объявляем общую переменную
Перем ОбновитьЭлемент;

Процедура ПриОткрытии()
    ОбновитьЭлемент = Неопределено;
КонецПроцедуры

Процедура ПолеВводаНоменклатурыПриИзменении(Элемент)
    // Здесь ваша логика обработки введенных данных
    // ...

    // После обработки данных устанавливаем переменную, указывающую на наш элемент
    ОбновитьЭлемент = Элемент; 
КонецПроцедуры

Процедура ПриОбновленииОтображения()
    Если ОбновитьЭлемент <> Неопределено Тогда
        ЭтаФорма.ТекущийЭлемент = ОбновитьЭлемент;
        ОбновитьЭлемент = Неопределено; // Сбрасываем переменную, чтобы не было постоянного обновления
    КонецЕсли;
КонецПроцедуры

Разберем этот подход:

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

Этот метод использует асинхронность события ПриОбновленииОтображения, которое срабатывает позже, чем прямые обработчики изменения поля, позволяя корректно вернуть фокус.

Менее эффективные и неработающие методы

В процессе поиска решения пользователи пробовали и другие методы, которые оказались неэффективными или вовсе не работающими для управляемых форм:

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

Рекомендации и лучшая практика

Исходя из нашего анализа, для большинства сценариев в современных версиях платформы 1С:Предприятие 8.3 (особенно для управляемых форм и работы в Web-клиенте) самым стабильным и "софтверным" методом остается комбинация:

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

Для обычных форм, помимо аналогичного подхода с обработчиком ожидания, можно рассмотреть вариант с использованием глобальной переменной и события ПриОбновленииОтображения.

Всегда тестируйте выбранное решение на вашей конкретной версии платформы и в реальном окружении, так как поведение может немного варьироваться.

← На главную