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

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

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

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

Проанализируем ситуацию, описанную в исходном коде. Когда мы запускаем цикл Для каждого на клиенте, управление полностью передается встроенному языку 1С. Клиентское приложение в этот момент занято выполнением инструкций кода и не может обрабатывать системные сообщения операционной системы о перерисовке графического интерфейса. Несмотря на то, что значение ЭтаФорма.Состояние меняется в памяти, платформа визуально отобразит это изменение только в момент «паузы», когда процедура Заполнить завершит свою работу и вернет управление системе.

Кроме того, вызов серверной процедуры ЗаполнитьНаСервере(Стр.Ссылка) внутри цикла на клиенте является крайне неоптимальным. Это порождает множество сетевых вызовов (round-trip) между клиентом и сервером, что значительно замедляет общую работу программы. Рассмотрим, как можно сделать интерфейс отзывчивым.

Способ 1. Использование системного метода Состояние()

Самый простой и быстрый способ «оживить» форму — использовать встроенную функцию Состояние(). Этот метод принудительно заставляет платформу обновить системную строку состояния в нижнем углу окна, не дожидаясь окончания выполнения процедуры.

Рассмотрим пример кода, который решает задачу минимальными правками:


&НаКлиенте
Процедура Заполнить(Команда)
    ВсегоЭлементов = Объект.ТЧ.Количество();
    Счетчик = 0;
    
    Для каждого Стр из Объект.ТЧ цикл
        Счетчик = Счетчик + 1;
        Процент = (Счетчик / ВсегоЭлементов) * 100;
        
        // Обновляем строку состояния и шкалу прогресса
        Состояние("Обработка строк...", Процент, "Обрабатывается: " + Стр.Ссылка);
        
        ЗаполнитьНаСервере(Стр.Ссылка);
    КонецЦикла;
КонецПроцедуры

Метод Состояние() принимает несколько параметров: текст сообщения, числовое значение прогресса (от 0 до 100), пояснение и картинку. Если передать второй параметр, 1С автоматически отобразит визуальный индикатор (прогресс-бар), что очень удобно для пользователя.

Способ 2. Использование обработчика ожидания

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

  1. Подготавливаем массив данных для обработки и помещаем его во временное хранилище или реквизит формы.
  2. Подключаем обработчик ожидания с небольшим интервалом (например, 0.1 секунды).
  3. В процедуре обработчика берем одну или несколько строк, обрабатываем их и обновляем реквизиты формы.
  4. Завершаем процедуру обработчика, тем самым давая платформе возможность перерисовать интерфейс.

Посмотрим на пример реализации:


&НаКлиенте
Перем ИндексТекущейСтроки;

&НаКлиенте
Процедура НачатьЗаполнение(Команда)
    ИндексТекущейСтроки = 0;
    // Подключаем обработчик ожидания
    ПодключитьОбработчикОжидания("ОбработатьСледующуюСтроку", 0.1, Истина);
КонецПроцедуры

&НаКлиенте
Процедура ОбработатьСледующуюСтроку()
    Если ИндексТекущейСтроки < Объект.ТЧ.Количество() Тогда
        ТекСтрока = Объект.ТЧ[ИндексТекущейСтроки];
        
        // Обновляем реквизит формы, который видит пользователь
        ТекущийСтатусНаФорме = "Обработка: " + ТекСтрока.Ссылка;
        
        // Выполняем полезную работу
        ЗаполнитьНаСервере(ТекСтрока.Ссылка);
        
        ИндексТекущейСтроки = ИндексТекущейСтроки + 1;
        
        // Снова подключаем обработчик для следующей итерации
        ПодключитьОбработчикОжидания("ОбработатьСледующуюСтроку", 0.1, Истина);
    Иначе
        ТекущийСтатусНаФорме = "Обработка завершена!";
    КонецЕсли;
КонецПроцедуры

Этот метод делает форму полностью интерактивной: пользователь может не только видеть прогресс, но и нажимать другие кнопки или даже отменить процесс, если вы предусмотрите соответствующую проверку.

Способ 3. Фоновые задания и БСП (Профессиональный подход)

В современных конфигурациях (УТ 11, БСП, ERP) наиболее правильным считается использование фоновых заданий. Это позволяет вынести тяжелые расчеты на сервер, не блокируя клиентское приложение вовсе. Рассмотрим, как это работает через механизмы Библиотеки Стандартных Подсистем (БСП).

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

Шаги реализации в фоновом задании на сервере:


// В серверном модуле
Процедура ВыполнитьОбработку(Параметры, АдресРезультата) Экспорт
    ТЧ = Параметры.ТабличнаяЧасть;
    Всего = ТЧ.Количество();
    
    Для Счетчик = 0 По Всего - 1 Цикл
        // Выполняем код
        // ...
        
        // Сообщаем прогресс
        ТекстСообщения = "Обработано " + Счетчик + " из " + Всего;
        Процент = (Счетчик / Всего) * 100;
        ДлительныеОперации.СообщитьПрогресс(Процент, ТекстСообщения);
    КонецЦикла;
КонецПроцедуры

На клиенте мы используем метод ДлительныеОперацииКлиент.ОжидатьЗавершения(), который берет на себя всю работу по опросу сервера и обновлению стандартного окна индикации. Это избавляет разработчика от необходимости вручную настраивать обработчики ожидания и следить за состоянием потоков.

Заключение и рекомендации

Выбор метода зависит от сложности вашей задачи:

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

← На главную