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