Почему метод ТекущийЭлемент не устанавливает курсор в поле ввода в 1С и как это исправить?

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

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

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

Выясняем техническую причину проблемы

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

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

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

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

Рассмотрим несколько эффективных способов решения этой проблемы.

Решение 1. Использование однократного обработчика ожидания

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

Разберем по шагам, как это реализовать:

Шаг 1. В обработчике события, где происходит обработка ввода (например, при изменении поля ввода серийного номера), вместо прямой установки фокуса подключим однократный обработчик ожидания с минимальной задержкой:


Процедура ПолеВводаСерийникПриИзменении(Элемент)
    
    // Здесь выполняется ваша логика обработки ввода (например, подбор товара)
    ОбработатьВводСерийногоНомера(Элемент.Значение);
    
    // Подключаем однократный обработчик ожидания. 
    // Третий параметр "Истина" указывает, что обработчик выполнится только один раз.
    ПодключитьОбработчикОжидания("УстановитьФокусНаПолеВвода", 0.1, Истина);
    
КонецПроцедуры

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


Процедура УстановитьФокусНаПолеВвода() Экспорт
    
    // Возвращаем фокус на наше исходное поле ввода
    ЭтаФорма.ТекущийЭлемент = ЭлементыФормы.ПолеВводаСерийник;
    
КонецПроцедуры

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

Решение 2. Отмена стандартной обработки в событии «ОкончаниеВводаТекста»

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

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

Проанализируем пример реализации:


Процедура ПолеВводаСерийникОкончаниеВводаТекста(Элемент, Текст, ДанныеВыбора, СтандартнаяОбработка)
    
    // Отменяем стандартное поведение платформы по клавише Enter
    СтандартнаяОбработка = Ложь;
    
    // Выполняем логику поиска и добавления номенклатуры
    ДобавитьТоварПоСерийномуНомеру(Текст);
    
    // Очищаем поле для нового ввода (при необходимости)
    Элемент.Значение = "";
    
    // Принудительно оставляем фокус в текущем поле
    ЭтаФорма.ТекущийЭлемент = ЭлементыФормы.ПолеВводаСерийник;
    
КонецПроцедуры

Так как мы установили параметр СтандартнаяОбработка в значение Ложь, платформа не будет пытаться перевести фокус на следующий элемент формы после нажатия Enter, и курсор мгновенно останется в нужном поле.

Решение 3. Мгновенный сброс состояния видимости элемента

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

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

Рассмотрим, как выглядит этот код:


Процедура ПолеВводаСерийникПриИзменении(Элемент)
    
    // Обработка логики ввода
    ДобавитьСерийныйНомерВДокумент(Элемент.Значение);
    
    // Быстро переключаем видимость для сброса состояния фокуса
    ЭлементыФормы.ПолеВводаСерийник.Видимость = Ложь;
    ЭлементыФормы.ПолеВводаСерийник.Видимость = Истина;
    
    // Устанавливаем фокус
    ЭтаФорма.ТекущийЭлемент = ЭлементыФормы.ПолеВводаСерийник;
    
КонецПроцедуры

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

Решение 4. Изменение свойства «Поведение клавиши Enter» для формы

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

Посмотрим, как это настроить в конфигураторе:

  1. Откройте нужную форму в режиме конфигуратора.
  2. Перейдите в палитру свойств самой формы.
  3. Найдите свойство «Поведение клавиши Enter» (в некоторых версиях платформы оно может называться связанным с кнопкой по умолчанию).
  4. Измените его значение на «Кнопка по умолчанию».
  5. Убедитесь, что на форме нет кнопки, для которой установлено свойство КнопкаПоУмолчанию = Истина (или назначьте такую кнопку и сделайте ее обработчик перехватчиком ввода).

При такой настройке нажатие клавиши Enter больше не будет вызывать автоматический переход по цепочке элементов (Tab-order), и фокус останется ровно там, где вы указали его в коде.

Решение 5. Особенности работы внутри табличных частей

Ситуация значительно усложняется, если поле ввода находится не на самой форме, а внутри строки табличной части (например, при построчном вводе кодов маркировки или серийных номеров в табличное поле). В этом случае фокус может слетать из-за закрытия режима редактирования строки.

Чтобы победить эту проблему, необходимо дублировать установку фокуса сразу в двух событиях:

  1. В обработчике события ПриИзменении конкретной колонки табличной части.
  2. В обработчике события ПриОкончанииРедактирования самого табличного поля.

Проанализируем пример комплексной обработки:


Процедура ТабличнаяЧастьТоварыСерийныйНомерПриИзменении(Элемент)
    
    // Устанавливаем признак необходимости вернуть фокус
    мНужноВернутьФокус = Истина;
    
КонецПроцедуры

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

Использование переменной модуля формы мНужноВернутьФокус позволяет точно координировать действия платформы и не давать фокусу покидать редактируемую ячейку таблицы.

Резюме

Мы рассмотрели пять различных подходов к решению проблемы с потерей фокуса в новых версиях платформы 1С. Каждый из них имеет свои особенности:

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

← На главную