Сообщения, вопросы и оповещения в 1С: какой метод выбрать и как его вызвать
Содержание
Чтобы вывести предупреждение пользователю в 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.
Индикатор на форме и длительные операции
Если обработка идёт на сервере, Состояние() из серверного кода не обновит экран: клиент ждёт возврата вызова. Для долгих операций правильная схема такая:
- Запустить работу фоновым заданием.
- На форме разместить элемент «Поле индикатора», связанный с числовым реквизитом формы.
- Периодически опрашивать задание через
ПодключитьОбработчикОжиданияи обновлять реквизит.
В БСП это готово: в фоновой процедуре вызывают ДлительныеОперации.СообщитьПрогресс(Процент, Текст), а на клиенте прогресс показывает форма ожидания длительной операции.
Остановить действие: Отказ, исключение и блокирующая форма
Иногда пользователя надо не просто предупредить, а не пустить дальше.
Отказ в обработчике события. В ПередЗаписью, ОбработкаПроверкиЗаполнения, ОбработкаПроведения выставляют Отказ = Истина и выводят сообщение через СообщениеПользователю. Запись отменится, а текст причины появится в окне сообщений с привязкой к полю.
Исключение. ВызватьИсключение "Текст"; прерывает выполнение, откатывает транзакцию и показывает окно ошибки. Этот вариант годится для ситуаций, которые не должны случаться при нормальной работе: нет обязательной настройки, нарушена целостность данных. Для ошибок заполнения он груб: пользователь видит окно ошибки вместо понятной подсказки у поля.
Своя форма с блокировкой. Если стандартного окна мало (нужны картинка, ссылка, флажок «больше не показывать»), создают форму и открывают её в режиме блокировки:
ОткрытьФорму("ОбщаяФорма.ВажноеПредупреждение", , ЭтотОбъект, , , ,
Новый ОписаниеОповещения("ПослеЗакрытияПредупреждения", ЭтотОбъект),
РежимОткрытияОкнаФормы.БлокироватьВесьИнтерфейс);
Режим БлокироватьОкноВладельца закрывает доступ только к вызвавшей форме, БлокироватьВесьИнтерфейс — ко всему приложению. Код после ОткрытьФорму всё равно выполнится сразу, продолжение пишут в обработчике закрытия.
Какой способ вывода сообщения пользователю выбрать
| Метод | Где работает | Ждёт реакции | Когда применять |
|---|---|---|---|
Сообщить | клиент и сервер | нет | итог операции, отладка |
СообщениеПользователю | клиент и сервер | нет | ошибки заполнения с привязкой к полю |
ПоказатьПредупреждение | клиент | закрытие окна | важная информация, которую нельзя пропустить |
ПоказатьВопрос | клиент | выбор кнопки | подтверждение перед действием |
ПоказатьОповещениеПользователя | клиент | нет | фоновое «готово», ссылка на созданный объект |
Состояние | клиент | нет | прогресс клиентского цикла |
Отказ = Истина + сообщение | обработчики событий | — | запрет записи или проведения |
ВызватьИсключение | клиент и сервер | закрытие окна ошибки | нештатная ситуация, откат транзакции |
Простое правило: чем меньше сообщение требует от пользователя, тем мягче способ. Окно с кнопкой на каждое «Готово» быстро приучает людей жать «ОК», не читая, и важное предупреждение потом тоже пролистают.
Веб-клиент и мобильное приложение
В веб-клиенте модальные окна браузера не поддерживаются так, как в тонком клиенте. Поэтому весь код, который должен работать в браузере, пишут на немодальных методах или на Асинх/Ждать. Конфигурация с режимом модальности «Не использовать» ведёт себя одинаково в обоих клиентах — это ещё один довод его не трогать.
Ещё несколько отличий браузера:
- 🌐 оповещения в углу и окно сообщений работают, но выглядят в стилях веб-клиента;
- 🌐 долгий серверный вызов браузер может оборвать по своему таймауту, поэтому прогресс длинных операций показывают только через фоновое задание;
- 🌐 блокировщик всплывающих окон в браузере иногда мешает открывать формы в отдельных окнах — пользователю нужно разрешить их для адреса публикации.
В мобильной платформе модальных методов нет совсем, так что подходят только ПоказатьПредупреждение, ПоказатьВопрос и асинхронные функции. Длинный текст в маленьком окне читать неудобно: на телефоне держите предупреждения в одну-две фразы, подробности выносите в форму.
Частые вопросы
Можно ли выделить текст в Сообщить цветом или жирным?
Как вывести многострочное предупреждение?
Символы.ПС: "Первая строка" + Символы.ПС + "Вторая строка". Это работает и в предупреждении, и в вопросе, и в окне сообщений.Почему сообщение с сервера пришло только после окончания обработки?
Как показать предупреждение при открытии формы?
ПриОткрытии вызовите ПоказатьПредупреждение. Если окно должно появиться после полной отрисовки формы, подключите обработчик ожидания на 0,1 секунды и вызовите предупреждение из него.