Как реализовать индикатор прогресса (прогресс-бар) во внешней обработке в 1С 8.3

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

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

Различие между «кружком» и «полоской»

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

Способ 1: Использование метода Состояние

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

Рассмотрим синтаксис этого метода:

Состояние(ТекстСостояния, Процент, Пояснение, Картинка)

Для того чтобы на экране появилась именно полоска, нам необходимо передать во второй параметр числовое значение от 0 до 100. Разберем на примере небольшого цикла в модуле формы:


&НаКлиенте
Процедура ВыполнитьОбработку()
    ВсегоИтераций = 1000;
    Для Счетчик = 1 По ВсегоИтераций Цикл
        // Выполняем полезную работу
        Процент = (Счетчик / ВсегоИтераций) * 100;
        Состояние("Обработка данных...", Процент, "Выполняется шаг " + Счетчик);
    КонецЦикла;
КонецПроцедуры

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

Способ 2: Реализация индикатора на форме через фоновое задание

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

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

  1. Создадим на форме реквизит Прогресс с типом Число.
  2. Разместим его на форме и установим свойство Вид в значение Поле индикатора.
  3. В коде будем использовать фоновое задание, которое будет записывать прогресс, а клиентская форма — считывать его.

Для передачи прогресса из фонового задания на сервер используется метод СообщитьПрогресс(). Рассмотрим, как реализовать «мост» в общем модуле для запуска внешней обработки:


// В общем модуле (например, ОбщегоНазначения)
Процедура ЗапуститьМетодВнешнейОбработки(ПутьКФайлу, ИмяМетода, Параметры) Экспорт
    Обработка = ВнешниеОбработки.Создать(ПутьКФайлу, Ложь);
    Выполнить("Обработка." + ИмяМетода + "(Параметры)");
КонецПроцедуры

Теперь в модуле самой внешней обработки мы можем использовать передачу прогресса:


// В модуле объекта внешней обработки
Процедура ДлительнаяОперация(Параметры) Экспорт
    Для Индекс = 1 По 100 Цикл
        // Выполняем расчеты
        СообщитьПрогресс(Индекс, "Выполнение шага " + Индекс);
    КонецЦикла;
КонецПроцедуры

Способ 3: Механизмы БСП (Библиотека стандартных подсистем)

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

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


&НаКлиенте
Процедура ВыполнитьДлительнуюОперацию()
    Результат = ДлительныеОперации.ЗапуститьВыполнениеВФоне(УникальныйИдентификатор, "ИмяОбщегоМодуля.ИмяПроцедуры", Параметры);
    Если Результат.Статус = "Выполняется" Тогда
        ИдентификаторЗадания = Результат.ИдентификаторЗадания;
        ПодключитьОбработчикОжидания("ПроверитьВыполнениеЗадания", 1, Ложь);
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура ПроверитьВыполнениеЗадания()
    Статус = ДлительныеОперации.ПрочитатьПрогресс(ИдентификаторЗадания);
    Если Статус.Свойство("Процент") Тогда
        ЭтотОбъект.ИндикаторПрогресса = Статус.Процент;
    КонецЕсли;
    
    // Проверка завершения задания...
КонецПроцедуры

Оптимизация производительности: почему прогресс-бар замедляет работу?

Рассмотрим ситуацию, упомянутую опытными разработчиками: добавление индикатора прогресса может увеличить время выполнения обработки (например, с 2 часов до 3). Проанализируем причину этого явления.

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

Чтобы избежать этой проблемы, применим метод «шагового обновления». Разберем пример оптимизированного цикла:


&НаСервере
Процедура ОптимизированныйЦикл()
    Всего = Объект.ДанныеДляОбработки.Количество();
    ШагОбновления = Цело(Всего / 100); // Обновляем прогресс только при изменении на 1%
    Если ШагОбновления = 0 Тогда ШагОбновления = 1; КонецЕсли;

    Для Индекс = 0 По Всего - 1 Цикл
        // Основной код
        
        Если Индекс % ШагОбновления = 0 Тогда
            Процент = Цело((Индекс / Всего) * 100);
            СообщитьПрогресс(Процент, "Обработано строк: " + Индекс);
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

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

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

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

  1. Для простых клиентских скриптов используйте Состояние(). Это быстро и не требует доработки конфигурации.
  2. Для профессиональных решений во внешних обработках используйте фоновые задания. Это позволит пользователю продолжать работу с системой, пока идет расчет.
  3. Если доступна БСП — всегда используйте ДлительныеОперации. Это стандарт де-факто в современной разработке на платформе 1С 8.3.
  4. Всегда следите за частотой обновления индикатора. Помните: прогресс-бар нужен для комфорта пользователя, а не для создания дополнительной нагрузки на сервер.

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

← На главную