К статье
Практический материал

Разработка и Конфигурация · 10 мин

Как сделать прогресс-бар в 1С

Как сделать прогресс-бар в 1С: индикатор длительной операции через Индикатор, Состояние и ДлительныеОперации. Примеры кода для обычных и управляемых форм.

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

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

Ниже разобраны рабочие варианты с примерами кода, их ограничения и типичные ошибки, из-за которых индикатор «замирает» или не обновляется вовсе.

Какие способы показать прогресс существуют в 1С

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

Сравнение вариантов

Функция Индикатор()

Простейший код, но работает только в обычном приложении и толстом клиенте. Не подходит для тонкого и веб-клиента.

Элемент формы «Индикатор»

Работает в управляемых формах, но требует обновления реквизита и периодических вызовов сервера, что при интенсивном цикле нагружает соединение.

ДлительныеОперации (БСП)

Штатный вариант для серверных процедур: прогресс передаётся из фонового задания, интерфейс не блокируется. Требует встроенной БСП.

Состояние()

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

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

Прогресс-бар в обычных формах через Индикатор()

Самый короткий способ — функция Индикатор(Пояснение, Процент). Она выводит полосу прогресса в строку состояния главного окна. Первый параметр — текст пояснения, второй — число от 0 до 100. Вызов с пустым пояснением или без параметров скрывает индикатор.

Процедура ОбработатьДокументы(Команда)

Запрос = Новый Запрос("ВЫБРАТЬ Ссылка ИЗ Документ.РеализацияТоваровУслуг");

Выборка = Запрос.Выполнить().Выбрать();

Всего = Выборка.Количество();

Счетчик = 0;

Пока Выборка.Следующий() Цикл

Счетчик = Счетчик + 1;

// ... обработка документа ...

Процент = Окр(Счетчик / Всего * 100, 0);

Индикатор("Обработано " + Счетчик + " из " + Всего, Процент);

КонецЦикла;

Индикатор(); // скрыть индикатор

КонецПроцедуры

Ключевой момент — заранее знать общее количество итераций. Если размер выборки неизвестен, сначала выполняют запрос с Количество() или предварительную выборку, иначе процент вычислить невозможно. Обновлять индикатор на каждой итерации не обязательно: при миллионах записей разумно обновлять раз в 100–500 итераций — визуально разницы нет, а накладные расходы меньше.

Индикатор в управляемой форме через элемент «Индикатор»

В управляемой форме полосу прогресса рисует элемент формы с видом «Поле индикатора». Порядок настройки: добавьте в реквизиты формы число (например, ПрогрессВыполнения, тип Число, минимальное значение 0, максимальное 100), перетащите его на форму и в свойствах элемента установите вид «Поле индикатора». Дальше достаточно менять значение реквизита — платформа перерисует полосу.

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

&НаКлиенте

Процедура НачатьОбработку(Команда)

ТекущийИндекс = 0;

ПодключитьОбработчикОжидания("ОбработатьПорцию", 0.1, Истина);

КонецПроцедуры

&НаКлиенте

Процедура ОбработатьПорцию()

РазмерПорции = 50;

ОбработатьПорциюНаСервере(ТекущийИндекс, РазмерПорции, ВсегоЗаписей);

ТекущийИндекс = ТекущийИндекс + РазмерПорции;

ПрогрессВыполнения = Окр(ТекущийИндекс / ВсегоЗаписей * 100, 0);

Если ТекущийИндекс < ВсегоЗаписей Тогда

ПодключитьОбработчикОжидания("ОбработатьПорцию", 0.1, Истина);

Иначе

ПрогрессВыполнения = 100;

КонецЕсли;

КонецПроцедуры

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

Прогресс фонового задания через ДлительныеОперации БСП

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

Процедура ДлительнаяОбработка(Параметры, АдресРезультата) Экспорт

Всего = Параметры.КоличествоЗаписей;

Для Счетчик = 1 По Всего Цикл

// ... обработка ...

ДлительныеОперации.СообщитьПрогресс(

Окр(Счетчик / Всего * 100, 0),

"Обработано " + Счетчик + " из " + Всего);

КонецЦикла;

КонецПроцедуры

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

Порядок действий для БСП
  1. 1
    Перенесите обработку в серверную процедуру общего модуля с признаком «Вызов сервера» и длительной операции
  2. 2
    Внутри цикла вызывайте ДлительныеОперации.СообщитьПрогресс с процентом и пояснением
  3. 3
    На клиенте запустите операцию через ДлительныеОперации.ВыполнитьВФоне
  4. 4
    Подключите ожидание через ДлительныеОперации.ОжидатьЗавершение с оповещением
  5. 5
    В обработчике оповещения проверьте статус и разберите результат из адреса хранилища

Текстовое состояние как минимальный вариант

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

Состояние("Идёт загрузка данных", Окр(Счетчик / Всего * 100, 0), "Запись " + Счетчик);

// после завершения:

Состояние();

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

Проверка результата и типичные ошибки

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

Контрольные точки

Как проверить результат

Обновление полосы
Норма

Процент растёт по мере обработки, интерфейс отвечает

Тревожный признак

Полоса стоит на 0% и прыгает в конец — обновление происходит только после завершения серверного вызова

Завершение
Норма

Индикатор скрыт вызовом Индикатор() или сбросом реквизита

Тревожный признак

Полоса остаётся на форме после окончания обработки

Поведение при ошибке
Норма

При исключении индикатор скрывается, пользователь видит сообщение

Тревожный признак

После ошибки индикатор «висит», создавая видимость продолжающейся работы

Типичные ошибки
01
Длинный цикл целиком в серверной процедуре управляемой формы — клиент видит обновление только в конце, полоса не двигается
02
Индикатор() в коде, который запускается на тонком клиенте, — вызов молча игнорируется, прогресса нет
03
Отсутствие скрытия индикатора при исключении — после ошибки полоса остаётся на экране; оборачивайте цикл в Попытка/Исключение с очисткой
04
Обновление прогресса на каждой итерации при миллионах записей — лишние вызовы и мерцание; обновляйте порциями
05
Процент вычисляется от неизвестного общего числа — полоса «перепрыгивает» или уходит за 100%

Отдельная рекомендация — всегда оборачивать цикл с индикатором в конструкцию Попытка ... Исключение ... КонецПопытки и в ветке исключения скрывать индикатор и сбрасывать состояние. Иначе любая ошибка в середине обработки оставит пользователя с «вечным» прогресс-баром.

Частые вопросы

Почему индикатор не двигается в управляемой форме?

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

Работает ли Индикатор() на тонком и веб-клиенте?

Нет, функция предназначена для обычного приложения и толстого клиента. В тонком и веб-клиенте вызов игнорируется без ошибки, поэтому код не упадёт, но и прогресс не покажет. Для этих клиентов используйте элемент формы «Индикатор» или длительные операции.

Как показать прогресс, если общее количество итераций неизвестно?

Точный процент вычислить нельзя. Варианты: сначала выполнить запрос количества, показывать только счётчик обработанных записей без процента, либо использовать «неопределённый» режим — текстовое состояние с пояснением, что процесс идёт.

Можно ли дать пользователю кнопку отмены?

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

Замедляет ли обновление индикатора саму обработку?

При обновлении на каждой итерации накладные расходы заметны на больших объёмах, особенно в клиент-серверном варианте. Обновляйте прогресс раз в 100–500 итераций или по таймеру — визуально это неотличимо, а нагрузка снижается.

Итог

Что важно запомнить

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