Переход на новые релизы платформы 1С часто преподносит сюрпризы, особенно когда речь идет о поддержке «классики», такой как Управление производственным предприятием (УПП). Одной из наиболее острых проблем в ветке 8.3.27.* стала потеря фокуса в обычных формах (Thick Client) после выполнения интерактивных действий. В частности, в форме подбора товаров после выбора позиции и закрытия модального окна (или окна ввода количества) фокус «улетает», и пользователь больше не может перемещаться по списку стрелками или переходить между полями клавишей Tab. Рассмотрим подробно, почему это происходит и как мы можем исправить эту ситуацию программно.
Прежде чем приступать к кодингу, давайте разберем природу бага. В платформе 8.3.27 был проведен масштабный рефакторинг механизмов взаимодействия оконных дескрипторов Windows. В обычных формах это привело к тому, что при закрытии дочернего окна фокус не возвращается корректно на родительскую форму. Визуально форма кажется активной, но системный фокус ввода находится «в никуда». Пользователю приходится делать лишний клик мышкой, что в условиях потоковой выписки накладных крайне негативно сказывается на производительности труда.
Данная проблема официально признана ошибкой платформы и проявляется в конфигурациях с режимом совместимости ниже 8.3.24, работающих на ядре 8.3.27. Поскольку УПП 1.3 является конфигурацией на обычных формах, она попадает в зону риска в первую очередь.
Самый простой и элегантный способ, который мы можем применить — это принудительная переустановка фокуса на активный элемент формы в конце процедуры обработки выбора. Часто параллельно с исправлением фокуса разработчики внедряют механизмы, позволяющие копировать и вставлять табличную часть из буфера обмена для ускорения заполнения документов. Проанализируем пример кода, который помогает «разбудить» форму:
// В процедуре ОбработкаВыбора или в месте завершения подбора
текАктивныйЭлемент = ЭтаФорма.ТекущийЭлемент;
// Переносим фокус на любой другой элемент, например, вспомогательную кнопку
ЭтаФорма.ТекущийЭлемент = ЭлементыФормы.кнСправка;
// Возвращаем фокус на исходный элемент списка или поле ввода
ЭтаФорма.ТекущийЭлемент = текАктивныйЭлемент;
Рассмотрим, почему это работает. При присвоении значения свойству ТекущийЭлемент платформа инициирует внутренние механизмы WinAPI для передачи фокуса. Двойная смена элемента заставляет систему принудительно обновить дескриптор активного окна.
Иногда прямое переключение фокуса в коде не срабатывает, так как платформа еще не успела полностью закрыть предыдущее модальное окно. В этом случае мы воспользуемся методом ПодключитьОбработчикОжидания. Разберем этот метод по шагам. В процессе работы с подбором товаров пользователям также может быть полезно копирование серийных номеров и их распределение между позициями, что требует стабильной работы интерфейса.
Создадим вспомогательную процедуру в модуле формы:
Процедура ВосстановитьФокусПослеПодбора() Экспорт
Если ТекущийЭлемент <> Неопределено Тогда
ЭтаФорма.Активизировать();
ЭтаФорма.ТекущийЭлемент = ТекущийЭлемент;
КонецЕсли;
КонецПроцедуры
А в месте, где происходит выбор товара (например, после открытия формы ввода количества), вызовем её с минимальной задержкой:
ПодключитьОбработчикОжидания("ВосстановитьФокусПослеПодбора", 0.1, Истина);
Важный нюанс: задержка в 0.1 секунды практически незаметна пользователю, но она дает платформе необходимые миллисекунды для завершения всех процессов перерисовки интерфейса, после чего фокус гарантированно вернется в нужное место.
Если штатные методы 1С не помогают, мы можем пойти по пути «обмана» операционной системы. Известно, что нажатие клавиши Alt или сочетания Alt+Tab часто возвращает фокус окну. Мы можем автоматизировать это с помощью WScript.Shell. Этот метод может пригодиться, когда в форму интегрированы сложные внешние компоненты, такие как подсказки Dadata для ввода адресов в УПП.
Посмотрим на пример реализации такого костыля:
Попытка
wsh = Новый COMОбъект("WScript.Shell");
// Симулируем нажатие клавиши ALT
wsh.SendKeys("%");
// Симулируем нажатие ESC для закрытия системного меню, если оно активировалось
wsh.SendKeys("{ESC}");
Исключение
// Обработка случая, если COM-объект недоступен (например, в Linux-клиенте)
ЗаписьЖурналаРегистрации("Ошибка восстановления фокуса", УровеньЖурналаРегистрации.Предупреждение);
КонецПопытки;
Разберем этот подход. Метод SendKeys отправляет нажатия клавиш непосредственно в очередь сообщений Windows. Несмотря на то что это решение считается «грязным», в условиях блокирующих багов платформы оно часто оказывается единственным рабочим вариантом для УПП.
Проанализируем ситуацию со стороны настроек самого приложения. Замечено, что проблема фокуса тесно связана с режимом отображения окон. Попробуйте изменить режим интерфейса:
В режиме отдельных окон логика управления фокусом на уровне операционной системы меняется, и в ряде случаев это полностью устраняет симптомы «зависания» стрелок в подборе.
Выясним, какой метод лучше выбрать. Если вы имеете возможность редактировать код подбора, мы рекомендуем использовать Решение №2 (Обработчик ожидания), так как оно наиболее стабильно и не зависит от наличия внешних библиотек в системе. В дополнение к исправлению фокуса, вы можете внедрить групповую обработку изображений, чтобы сделать визуальную работу с номенклатурой более удобной. Если же вы столкнулись с ситуацией, когда фокус теряется в типовом механизме, который нельзя менять — попробуйте Решение №4 с настройкой интерфейса.
Не забывайте, что работа с объектами ЭлементыФормы в обычном приложении требует внимательности к тому, какой именно элемент должен быть активным в данный момент. Всегда проверяйте, что ЭтаФорма.ТекущийЭлемент указывает на список товаров (табличное поле), прежде чем завершать процедуру выбора.