Как динамически обновлять данные на управляемой форме 1С без потери фокуса и перерисовки?

Программист 1С v8.3 (Управляемые формы)
← На главную

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

Почему происходит «перерисовка» и сброс фокуса?

Проанализируем ситуацию: управляемая форма в 1С работает по принципу разделения клиентской и серверной частей. Когда мы изменяем реквизит формы, связанный с элементом интерфейса, платформа инициирует механизм синхронизации данных. Даже если код выполняется полностью &НаКлиенте, изменение состояния элементов управления часто заставляет систему пересчитывать геометрию формы (Layout). В режиме совместимости с версией 8.2 этот процесс выражен наиболее остро: любое изменение заголовка декорации или значения реквизита может привести к полной перерисовке визуального дерева формы. В результате, если пользователь в этот момент набирает текст в другом поле, фокус теряется, а неоконченный ввод может сброситься к значению, которое было до начала редактирования.

Метод 1. Настройка свойства ОбновлениеТекстаРедактирования

Это самый простой способ, который позволяет минимизировать негативный эффект для пользователя без кардинальной переработки формы. Разберем по шагам, как это работает. У элементов управления типа ПолеВвода существует важное свойство — ОбновлениеТекстаРедактирования.

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

Рассмотрим пример настройки обработчика ожидания для обновления данных:


&НаКлиенте
Процедура ПриОткрытии(Отказ)
    // Подключаем опрос оборудования раз в 500 мс
    ПодключитьОбработчикОжидания("ОбновитьДанныеДатчика", 0.5, Ложь);
КонецПроцедуры

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

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

Метод 2. Использование Поля HTML документа (Рекомендуемый метод)

Если нам нужно действительно «точечное» обновление без затрагивания механизмов платформы 1С, лучше всего использовать ПолеHTMLДокумента. Этот метод позволяет обновлять только конкретный фрагмент страницы внутри элемента формы, используя JavaScript и объектную модель DOM. Для платформы это будет выглядеть как внутреннее действие браузера, которое не требует синхронизации всей формы.

Разберем алгоритм реализации этого метода:

  1. Создадим на форме реквизит с типом Строка (например, ДанныеHTML) и разместим его на форме как элемент с видом «Поле HTML документа».
  2. При создании формы сформируем базовую структуру HTML-страницы с уникальным идентификатором для блока вывода данных.
  3. В обработчике ожидания будем обращаться напрямую к этому блоку через JavaScript.

Пример кода для инициализации страницы:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    // Формируем минималистичный HTML
    ЭтаФорма.ДанныеHTML = 
        "<html>
        |<body style='margin:0; padding:0; overflow:hidden; font-family:Arial; font-size:14pt; font-weight:bold;'>
        |   <div id='weight_display' style='color:green;'>0.000 кг</div>
        |</body>
        |</html>";
КонецПроцедуры

Теперь реализуем процедуру обновления, которая будет работать молниеносно и незаметно для остального интерфейса:


&НаКлиенте
Процедура ОбновитьВесЧерезDOM()
    НовоеЗначение = Оборудование.ПолучитьВес(); // Получаем данные
    
    // Получаем доступ к документу HTML поля
    ДокументHTML = Элементы.ДанныеHTML.Документ;
    Если ДокументHTML <> Неопределено Тогда
        // Находим нужный элемент по ID и меняем его содержимое
        ЭлементОтображения = ДокументHTML.getElementById("weight_display");
        Если ЭлементОтображения <> Неопределено Тогда
            ЭлементОтображения.innerText = Строка(НовоеЗначение) + " кг";
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

Этот способ является наиболее профессиональным, так как он полностью изолирует процесс обновления визуальных данных от бизнес-логики формы 1С. Пользователь может вводить текст, переключать вкладки и работать с динамическими списками — поле HTML будет обновляться независимо, не вызывая пересчета интерфейса всей формы. По сути, это открывает дорогу для разработки пользовательских интерфейсов в 1С с использованием HTML, CSS, Vue.js и даже встраивания таких сложных элементов, как встраиваемая консоль кода.

Метод 3. Хранение данных в переменных модуля формы

Проанализируем еще одну архитектурную деталь. Часто разработчики совершают ошибку, записывая промежуточные данные датчиков в реквизиты формы. Но реквизиты формы — это объекты, которые 1С всегда стремится синхронизировать с сервером. Если нам нужно хранить текущее значение веса только для отображения, а записывать его в документ нужно только один раз (например, по нажатию кнопки «Зафиксировать»), мы можем использовать переменные модуля формы.

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


&НаКлиенте
Перем ПоследнееЗначениеВеса;

&НаКлиенте
Процедура ОбновитьВес()
    ТекВес = Оборудование.ПолучитьВес();
    
    // Обновляем визуализацию только если вес реально изменился
    Если ТекВес <> ПоследнееЗначениеВеса Тогда
        ПоследнееЗначениеВеса = ТекВес;
        // Здесь вызываем обновление через DOM (Метод 2)
        ОбновитьОтображение(ТекВес);
    КонецЕсли;
КонецПроцедуры

Выводы и рекомендации

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

  1. Избегайте использования Элементы.НазваниеДекорации.Заголовок для часто меняющихся данных, так как это гарантированно приведет к перерисовке всей формы.
  2. Для всех полей ввода, которые заполняет пользователь, установите ОбновлениеТекстаРедактирования в значение При изменении значения.
  3. Для частого обновления (чаще 1 раза в секунду) используйте Поле HTML документа и метод getElementById().innerText.
  4. Старайтесь выполнять опрос оборудования в асинхронном режиме или через внешние события (ВнешнееСобытие), чтобы не блокировать основной поток интерфейса, по аналогии с тем, как организуется индикация прогресса выполнения фонового задания.

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

← На главную