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

Программист 1С v8.3 (Управляемые формы) Управленческий учет Промышленность, строительство и АПК
← На главную

При разработке сложных интерфейсов, таких как автоматизированные рабочие места (АРМ) весовщиков или кассиров, программисты часто сталкиваются с необходимостью обновления данных на форме в реальном времени. Типичный сценарий: подключение весового оборудования, данные с которого должны считываться каждые 100 миллисекунд (0.1 сек). Однако здесь разработчиков подстерегает неприятный сюрприз — в строковые или числовые поля на этой же форме становится невозможно ввести данные: текст постоянно сбрасывается или поле очищается сразу после ввода. Проанализируем эту ситуацию и разберем, как обойти ограничения платформы.

Причина проблемы: конфликт буферов и цикл обновления формы

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

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

Решение 1: Настройка свойства «ОбновлениеТекстаРедактирования»

Самый простой и эффективный способ исправить поведение — изменить настройки самого элемента формы. Рассмотрим подробнее свойство ОбновлениеТекстаРедактирования (UpdateTextEditing). Оно определяет, в какой момент система должна синхронизировать текст в поле с данными реквизита.

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

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

Решение 2: Вывод данных через поле HTML-документа

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

Сначала подготовим процедуру в модуле формы для вызова из обработчика ожидания:


&НаКлиенте
Процедура ОбработкаОжиданияЭкспорт() Экспорт
    // Получаем данные с весов (в примере - генератор случайных чисел)
    ГСЧ = Новый ГенераторСлучайныхЧисел;
    НовыйВес = ГСЧ.СлучайноеЧисло(0, 500);
    
    // Передаем значение напрямую в HTML-поле без обновления реквизитов формы
    Элементы.ПолеВесаHTML.Документ.showWeight(НовыйВес);
    
    // Переподключаем обработчик для однократного вызова (точность 0.1 сек)
    ПодключитьОбработчикОжидания("ОбработкаОжиданияЭкспорт", 0.1, Истина);
КонецПроцедуры

Затем инициализируем HTML-разметку при открытии формы:


&НаКлиенте
Процедура ПриОткрытии(Отказ)
    ТекстHTML = "
    |<html>
    |<body style='margin:0; padding:0; font-family: sans-serif; font-size: 24px; color: green;'>
    |   <div id='weightDisplay'>0</div>
    |   <script>
    |       document.showWeight = function(weight) {
    |           document.getElementById('weightDisplay').innerHTML = weight + ' кг';
    |       };
    |   </script>
    |</body>
    |</html>";
    
    ПолеВесаHTML = ТекстHTML;
    ПодключитьОбработчикОжидания("ОбработкаОжиданияЭкспорт", 0.1, Истина);
КонецПроцедуры

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

Решение 3: Использование Декораций вместо Полей ввода

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

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


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

Такой метод позволяет избежать установки признака Модифицированность для всей формы при каждом тике таймера, что положительно сказывается на стабильности ввода в соседние поля.

Решение 4: Работа через переменные модуля формы

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


Перем ТекущийВесВПамяти;

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

Рекомендации по оптимизации частоты опроса

Частота 0.1 секунды (100 мс) является экстремальной для однопоточного пользовательского интерфейса 1С. Выполняя код так часто, мы забиваем очередь сообщений Windows событиями перерисовки. Рассмотрим рекомендации по оптимизации:

Подводя итог, можно сказать, что проблема «исчезающего текста» — это не баг платформы в чистом виде, а особенность синхронизации данных. Используя настройку ОбновлениеТекстаРедактирования или вывод через HTML/Декорации, вы сможете создать комфортный и отзывчивый интерфейс даже при работе с высокоскоростным оборудованием.

← На главную