Почему код в 1С работает по-разному в режиме предприятия и отладки и как исправить потерю фокуса?

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

В практике разработчика 1С иногда возникают ситуации, которые кажутся мистическими: один и тот же код ведет себя безупречно под отладкой, но ломает логику работы пользователя в обычном режиме. Одной из самых неприятных проблем такого рода является спонтанная потеря фокуса ввода. Рассмотрим ситуацию, когда после выполнения кода в обработчике ПриПолученииДанных курсор вместо того, чтобы остаться в поле подбора, «вылетает» в главное меню программы или на родительское окно. Проанализируем, почему это происходит и как это победить.

Выясним причину: почему отладка «скрывает» проблему?

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

В версиях платформы 8.3.26 и 8.3.27 был изменен алгоритм обработки сообщений Windows Messages, отвечающих за фокус элементов. В момент интенсивной перерисовки табличной части возникает конфликт приоритетов, и операционная система ошибочно передает фокус на верхний уровень иерархии — в главное меню. Именно поэтому при наборе текста у пользователя начинают открываться подменю «Сервис» или «Файл».

Почему же под отладкой всё работает? Когда мы ставим точку останова, выполнение потока прерывается. В этот момент фокус принудительно удерживается конфигуратором или системным отладчиком. После нажатия F5 платформа восстанавливает состояние окон из кэша, что фактически выполняет «принудительную» активацию нужного элемента. Таким образом, пауза в отладке дает платформе время корректно завершить системные процессы перерисовки, которые в обычном режиме «пролетают» с ошибкой фокуса.

Способ 1. Программное «перемигивание» фокусом

Если ваша конфигурация (например, УТ 10.3) работает на «проблемных» версиях платформы и вы не можете оперативно их обновить, можно использовать метод принудительного восстановления фокуса. Суть метода заключается в том, чтобы переключить фокус на вспомогательный элемент и тут же вернуть его обратно. Рассмотрим пример реализации такой процедуры:


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

В коде формы подбора, сразу после добавления строки или в конце процедур оформления, вызовем это восстановление. Проанализируем пример вызова:


// Пример вызова в обработчике события
ВосстановитьФокусВвода(ЭтаФорма, ЭлементыФормы.ДатаДокумента);

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

Способ 2. Использование обработчика ожидания (самый надежный «костыль»)

Как мы выяснили, проблема часто кроется в микро-задержках отрисовки. Мы можем искусственно разнести во времени процесс визуального обновления строки и процесс активации поля. Для этого идеально подходит ПодключитьОбработчикОжидания. Посмотрим, как это реализовать по шагам.

Шаг 1. Создадим экспортную процедуру в модуле формы, которая будет отвечать только за активацию поля ввода.


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

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


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

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

Способ 3. Управление версией платформы

Проанализируем ситуацию с точки зрения системного администрирования. Если программные методы не помогают, стоит рассмотреть изменение версии платформы 1С:Предприятие:

  1. Откат на стабильную версию: Практика показывает, что в ветке 8.3.24 данный баг отсутствует. Если специфика вашей конфигурации позволяет использовать эту версию, это будет самым «чистым» решением без внесения правок в код.
  2. Обновление до исправленных версий: Ошибка была признана разработчиками 1С и исправлена в тестовых сборках 8.5 и в последних патчах ветки 8.3.27 (сборки выше 19xx). Рекомендуем проверить актуальный список исправленных ошибок (Bugboard) для вашей конкретной сборки.

Дополнительные рекомендации

Иногда потеря фокуса сопровождается эффектом «залипшей клавиши Alt». Программа начинает воспринимать ввод символов как горячие клавиши меню. Если вы столкнулись именно с этим, попробуйте программно вызвать закрытие любого невидимого вспомогательного окна или использовать объект WScript.Shell для эмуляции нажатия клавиши Esc, что сбросит состояние меню. Однако, использование внешних объектов — это крайний метод, и мы рекомендуем в первую очередь использовать обработчик ожидания, так как он наиболее естественен для событийной модели 1С.

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

← На главную