Сообщения, вопросы и оповещения в 1С: какой метод выбрать и как его вызвать

· 9 мин

Содержание

Чтобы вывести предупреждение пользователю в 1С 8.3, в клиентском коде вызывают ПоказатьПредупреждение(, "Текст"): откроется окно с кнопкой «ОК», а код пойдёт дальше, не дожидаясь закрытия. Если сообщение не должно мешать работе, хватит Сообщить("Текст") — строка появится в окне сообщений внизу формы.

Частая ошибка — писать по старинке Предупреждение("Текст"). В современной конфигурации это даёт ошибку Использование модальных окон в данном режиме запрещено!, потому что модальные методы отключены свойством конфигурации. Ниже все способы показать пользователю сообщение, от самого мягкого до блокирующего, с кодом, который можно вставить в модуль формы.

Всё описанное относится к платформе 8.3 и управляемым формам (интерфейс «Такси»), от конкретной конфигурации не зависит.

Сообщить и СообщениеПользователю: текст в окне сообщений

Сообщить() — самый простой способ что-то сказать пользователю. Метод доступен и на клиенте, и на сервере. Сообщение, выданное на сервере, платформа передаёт на клиент после возврата из серверного вызова.

Сообщить("Документ проведён. Сумма: " + Формат(Сумма, "ЧДЦ=2"));

У метода есть второй параметр — статус (СтатусСообщения.Важное, СтатусСообщения.Внимание и другие). В управляемом приложении он на вид сообщения не влияет, поэтому на него не стоит полагаться как на «красный» текст.

Сообщение с привязкой к полю

Когда пользователь ошибся при заполнении, полезнее показать сообщение прямо у поля. Для этого используют объект СообщениеПользователю:

Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Не указан контрагент";
Сообщение.Поле = "Контрагент";
Сообщение.ПутьКДанным = "Объект";
Сообщение.Сообщить();

При щелчке по такому сообщению курсор перейдёт в поле «Контрагент», а само поле подсветится. Для строки табличной части путь собирают с индексом. Индексы начинаются с нуля, поэтому для НомерСтроки вычитают единицу:

Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = СтрШаблон("В строке %1 не указано количество", СтрокаТЧ.НомерСтроки);
Сообщение.Поле = "Товары[" + Формат(СтрокаТЧ.НомерСтроки - 1, "ЧГ=0") + "].Количество";
Сообщение.ПутьКДанным = "Объект";
Сообщение.Сообщить();

В модуле объекта (на сервере, при записи) вместо ПутьКДанным удобнее вызвать Сообщение.УстановитьДанные(ЭтотОбъект) — платформа сама найдёт открытую форму этого объекта.

Обёртка из БСП

В типовых конфигурациях на Библиотеке стандартных подсистем всё это уже обёрнуто:

  • 🖥 на сервере — ОбщегоНазначения.СообщитьПользователю(Текст, КлючДанных, Поле, ПутьКДанным, Отказ);
  • 💻 на клиенте — ОбщегоНазначенияКлиент.СообщитьПользователю(Текст, КлючДанных, Поле, ПутьКДанным, Отказ).

Последний параметр удобен в обработчиках ПередЗаписью и ОбработкаПроверкиЗаполнения: функция выставит Отказ = Истина одной строкой вместе с сообщением.

Сообщения из фонового задания

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

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

ПоказатьПредупреждение: окно, которое закрывают кнопкой

Если пользователь обязан увидеть текст, нужно окно поверх формы. Синтаксис:

ПоказатьПредупреждение(ОписаниеОповещения, ТекстПредупреждения, Таймаут, Заголовок);

Все параметры, кроме текста, необязательные. Простейший вызов:

ПоказатьПредупреждение(, "Остатки пересчитаны", , "Готово");

Главное отличие от старого Предупреждение() — метод не останавливает выполнение кода. Строка после вызова выполнится сразу, пока окно ещё открыто. Если что-то должно произойти только после нажатия «ОК», это переносят в обработчик оповещения:

&НаКлиенте
Процедура Пересчитать(Команда)
    ПересчитатьНаСервере();
    Оповещение = Новый ОписаниеОповещения("ПослеПредупреждения", ЭтотОбъект);
    ПоказатьПредупреждение(Оповещение, "Остатки пересчитаны. Форма будет закрыта.");
КонецПроцедуры

&НаКлиенте
Процедура ПослеПредупреждения(ДополнительныеПараметры) Экспорт
    Закрыть();
КонецПроцедуры

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

Параметр «Таймаут» задаётся в секундах: через это время окно закроется само. Удобно для информационных сообщений, которые не требуют реакции.

Модальность и асинхронные методы

Работа старых методов зависит от свойства конфигурации «Режим использования модальности» (открывается в конфигураторе, в свойствах корня конфигурации):

ЗначениеЧто происходит с Предупреждение()
Использоватьработает как раньше, код ждёт
Использовать с предупреждениямиработает, но платформа пишет предупреждения
Не использоватьошибка «Использование модальных окон в данном режиме запрещено!»

Не переключайте режим на «Использовать» в типовой конфигурации ради одной строки кода — это сломает работу в веб-клиенте и усложнит обновления. Правильный путь — переписать вызов на немодальный.

Начиная с платформы 8.3.18 есть третий вариант — асинхронные функции. Код читается как модальный, но окно не блокирует браузер:

&НаКлиенте
Асинх Процедура Пересчитать(Команда)
    ПересчитатьНаСервере();
    Ждать ПредупреждениеАсинх("Остатки пересчитаны");
    Закрыть();
КонецПроцедуры

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

ПоказатьВопрос: когда нужен ответ «Да» или «Нет»

Предупреждение только информирует. Если дальнейшие действия зависят от выбора пользователя, используют ПоказатьВопрос:

ПоказатьВопрос(ОписаниеОповещения, ТекстВопроса, Кнопки, Таймаут, КнопкаПоУмолчанию, Заголовок, КнопкаТаймаута);

Типовой пример — подтверждение удаления строк:

&НаКлиенте
Процедура ОчиститьТовары(Команда)
    Оповещение = Новый ОписаниеОповещения("ПослеОтветаНаВопрос", ЭтотОбъект);
    ПоказатьВопрос(Оповещение, "Удалить все строки табличной части?",
        РежимДиалогаВопрос.ДаНет, 0, КодВозвратаДиалога.Нет, "Подтверждение");
КонецПроцедуры

&НаКлиенте
Процедура ПослеОтветаНаВопрос(Результат, ДополнительныеПараметры) Экспорт
    Если Результат = КодВозвратаДиалога.Да Тогда
        Объект.Товары.Очистить();
    КонецЕсли;
КонецПроцедуры

У обработчика вопроса два параметра: результат (значение КодВозвратаДиалога) и дополнительные параметры. В предупреждении — только второй. Перепутать количество параметров — частая причина ошибки при вызове обработчика.

Наборы кнопок задаёт РежимДиалогаВопрос:

  • ✅ ДаНет и ДаНетОтмена — подтверждения;
  • ✅ ОКОтмена — продолжить или отказаться;
  • ✅ ПовторитьОтмена и ПрерватьПовторитьПропустить — повтор после сбоя.

Можно передать и свой список кнопок — СписокЗначений, где значение вернётся как результат, а представление станет надписью на кнопке:

Кнопки = Новый СписокЗначений;
Кнопки.Добавить("Сохранить", "Сохранить и закрыть");
Кнопки.Добавить("Закрыть", "Закрыть без сохранения");
Кнопки.Добавить(КодВозвратаДиалога.Отмена, "Отмена");

Асинхронный вариант для 8.3.18 и выше:

Ответ = Ждать ВопросАсинх("Удалить все строки?", РежимДиалогаВопрос.ДаНет);
Если Ответ = КодВозвратаДиалога.Да Тогда
    Объект.Товары.Очистить();
КонецЕсли;

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

Оповещение в углу экрана, строка состояния и индикатор

Не каждое сообщение заслуживает окна. Для фоновой информации есть два ненавязчивых механизма.

ПоказатьОповещениеПользователя

Всплывающее сообщение в правом нижнем углу, которое исчезает само. Так платформа сообщает «Изменение: Поступление товаров…» после записи.

ПоказатьОповещениеПользователя("Выгрузка завершена", , "Файл сохранён в каталог обмена",
    БиблиотекаКартинок.Информация);

Параметры по порядку: текст, действие при нажатии (навигационная ссылка или ОписаниеОповещения), пояснение, картинка. Если передать ссылку на документ, по щелчку на оповещении он откроется.

Состояние

Метод Состояние() выводит строку состояния с полосой прогресса. Применяют в длинных клиентских циклах:

Всего = СписокФайлов.Количество();
Для Сч = 1 По Всего Цикл
    Процент = Окр(Сч / Всего * 100);
    Состояние("Загрузка файлов", Процент, СтрШаблон("Обработано %1 из %2", Сч, Всего));
    ЗагрузитьФайл(СписокФайлов[Сч - 1]);
КонецЦикла;

Прогресс передают числом от 0 до 100. Пересчёт: при 37 файлах из 50 получится Окр(37 / 50 * 100) = 74.

Индикатор на форме и длительные операции

Если обработка идёт на сервере, Состояние() из серверного кода не обновит экран: клиент ждёт возврата вызова. Для долгих операций правильная схема такая:

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

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

Остановить действие: Отказ, исключение и блокирующая форма

Иногда пользователя надо не просто предупредить, а не пустить дальше.

Отказ в обработчике события. В ПередЗаписью, ОбработкаПроверкиЗаполнения, ОбработкаПроведения выставляют Отказ = Истина и выводят сообщение через СообщениеПользователю. Запись отменится, а текст причины появится в окне сообщений с привязкой к полю.

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

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

ОткрытьФорму("ОбщаяФорма.ВажноеПредупреждение", , ЭтотОбъект, , , ,
    Новый ОписаниеОповещения("ПослеЗакрытияПредупреждения", ЭтотОбъект),
    РежимОткрытияОкнаФормы.БлокироватьВесьИнтерфейс);

Режим БлокироватьОкноВладельца закрывает доступ только к вызвавшей форме, БлокироватьВесьИнтерфейс — ко всему приложению. Код после ОткрытьФорму всё равно выполнится сразу, продолжение пишут в обработчике закрытия.

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

МетодГде работаетЖдёт реакцииКогда применять
Сообщитьклиент и сервернетитог операции, отладка
СообщениеПользователюклиент и сервернетошибки заполнения с привязкой к полю
ПоказатьПредупреждениеклиентзакрытие окнаважная информация, которую нельзя пропустить
ПоказатьВопросклиентвыбор кнопкиподтверждение перед действием
ПоказатьОповещениеПользователяклиентнетфоновое «готово», ссылка на созданный объект
Состояниеклиентнетпрогресс клиентского цикла
Отказ = Истина + сообщениеобработчики событий—запрет записи или проведения
ВызватьИсключениеклиент и серверзакрытие окна ошибкинештатная ситуация, откат транзакции

Простое правило: чем меньше сообщение требует от пользователя, тем мягче способ. Окно с кнопкой на каждое «Готово» быстро приучает людей жать «ОК», не читая, и важное предупреждение потом тоже пролистают.

Веб-клиент и мобильное приложение

В веб-клиенте модальные окна браузера не поддерживаются так, как в тонком клиенте. Поэтому весь код, который должен работать в браузере, пишут на немодальных методах или на Асинх/Ждать. Конфигурация с режимом модальности «Не использовать» ведёт себя одинаково в обоих клиентах — это ещё один довод его не трогать.

Ещё несколько отличий браузера:

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

В мобильной платформе модальных методов нет совсем, так что подходят только ПоказатьПредупреждение, ПоказатьВопрос и асинхронные функции. Длинный текст в маленьком окне читать неудобно: на телефоне держите предупреждения в одну-две фразы, подробности выносите в форму.

Диагностика: выберите симптом

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

Можно ли выделить текст в Сообщить цветом или жирным?
Нет, обычное сообщение выводится простым текстом. Для оформленного текста создают свою форму с полем форматированного документа или используют форматированную строку в надписи.
Как вывести многострочное предупреждение?
Разделите строки символом Символы.ПС: "Первая строка" + Символы.ПС + "Вторая строка". Это работает и в предупреждении, и в вопросе, и в окне сообщений.
Почему сообщение с сервера пришло только после окончания обработки?
Клиент получает сообщения при возврате из серверного вызова. Пока процедура на сервере не закончилась, пользователь их не увидит. Для промежуточных сообщений нужен фоновый режим.
Как показать предупреждение при открытии формы?
В обработчике ПриОткрытии вызовите ПоказатьПредупреждение. Если окно должно появиться после полной отрисовки формы, подключите обработчик ожидания на 0,1 секунды и вызовите предупреждение из него.
Чем ПоказатьОповещениеПользователя лучше Сообщить для итогов операции?
Оповещение не остаётся в окне сообщений формы и не мешает следующим проверкам. К нему можно привязать ссылку на созданный документ, чтобы пользователь открыл его одним щелчком.