Вывод сообщений в 1С 8.3: от Сообщить() до оповещений
Содержание
Быстрый ответ: текст в окно сообщений выводит метод Сообщить(), а правильнее — объект СообщениеПользователю, потому что его можно привязать к конкретному полю формы. Диалог с кнопками «Да/Нет» — это Вопрос(), простое уведомление — Предупреждение(). В управляемом приложении модальные диалоги часто запрещены, поэтому вместо них пишут асинхронные ПоказатьВопрос() и ПоказатьПредупреждение().
Частая ошибка новичка — звать Предупреждение() из серверного модуля и получать ошибку «Метод не найден». Диалоги живут только на клиенте. А Сообщить() на сервере работает, но текст появится на экране не сразу, а после того как серверный вызов завершится. Ниже — все способы вывести сообщение в 1С 8.3 с примерами кода и разбором, когда какой уместен.
Окно сообщений: Сообщить() и СообщениеПользователю
Самый простой способ показать текст — глобальный метод Сообщить(). Строка попадает в окно сообщений внизу формы.
Сообщить("Документ проведён");
Сообщить("Проверьте склад", СтатусСообщения.Внимание);
Второй параметр задаёт значок: СтатусСообщения.Обычное, .Важное, .Внимание, .Информация. На практике его ставят редко.
Сообщить() считается устаревшим. Платформа при синтаксическом контроле подчёркивает его и советует перейти на СообщениеПользователю. Старый код из-за этого не ломается, но в новых обработках лучше сразу писать по-новому.
Объект СообщениеПользователю умеет то, чего не может Сообщить(): он привязывает текст к конкретному полю на форме. Пользователь кликает по сообщению — и курсор прыгает в проблемный реквизит.
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Не заполнен контрагент";
Сообщение.Поле = "Контрагент";
Сообщение.УстановитьДанные(Объект);
Сообщение.Сообщить();
Если проверка идёт в табличной части, путь к полю указывают с индексом строки:
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Нулевая цена";
Сообщение.Поле = "Товары[" + (Индекс) + "].Цена";
Сообщение.УстановитьДанные(Объект);
Сообщение.Сообщить();
Привязка работает только когда сообщение формируется в контексте объекта и его формы. Если вызвать СообщениеПользователю из общего модуля без данных, текст появится в окне, но клик по нему никуда не переведёт.
У объекта есть и свойство КодСообщения — произвольная строка-метка. По ней код на форме может отличить своё сообщение от чужого и, например, подсветить нужное поле вручную. В большинстве проверок он не нужен, но для сложных форм с перехватом сообщений пригождается.
Чтобы собрать число и текст в одну строку, не склеивайте их напрямую — приводите число к строке через Формат():
Сообщить("Обработано строк: " + Формат(Счётчик, "ЧГ=0"));
Ещё удобнее собирать текст из частей через СтрШаблон() — тогда не придётся расставлять плюсы и кавычки:
Сообщить(СтрШаблон("Обработано %1 из %2 строк", Счётчик, Количество));
Диалоги с пользователем: предупреждение и вопрос
Когда нужно остановить работу и дождаться реакции человека, используют диалоговые окна. Их два основных вида.
Предупреждение() показывает окно с одной кнопкой «ОК». Выполнение кода встаёт, пока пользователь не закроет окно.
Предупреждение("Сначала заполните дату");
Предупреждение("Время вышло", 10, "Внимание");
Второй параметр — таймаут в секундах (окно закроется само), третий — заголовок.
Вопрос() выводит окно с выбором и возвращает нажатую кнопку:
Ответ = Вопрос("Удалить документ?", РежимДиалогаВопрос.ДаНет);
Если Ответ = КодВозвратаДиалога.Да Тогда
// удаляем
КонецЕсли;
Набор кнопок задаёт перечисление РежимДиалогаВопрос: ДаНет, ДаНетОтмена, ОКОтмена, ПовторитьОтмена и другие. Результат сравнивают с КодВозвратаДиалога.
| Метод | Что показывает | Что возвращает |
|---|---|---|
Предупреждение() | текст и кнопку «ОК» | ничего |
Вопрос() | текст и набор кнопок | КодВозвратаДиалога |
ВвестиЗначение() | поле ввода | введённое значение |
ВвестиСтроку() | поле для текста | введённую строку |
Кроме выбора «Да/Нет», у платформы есть целое семейство методов ввода: ВвестиСтроку(), ВвестиЧисло(), ВвестиДату(), ВвестиЗначение(). Каждый открывает маленькое окно, где пользователь что-то вводит, а метод возвращает результат (или Неопределено, если нажали «Отмена»).
Строка = "";
Если ВвестиСтроку(Строка, "Комментарий к документу", 150) Тогда
Объект.Комментарий = Строка;
КонецЕсли;
Первый аргумент передаётся по ссылке и получает введённое значение, а сам метод возвращает Истина, когда пользователь нажал «ОК». Это тоже модальные методы — в управляемом приложении у них есть асинхронные версии Показать*.
Предупреждение и Вопрос — это модальные методы. В типовых конфигурациях на «Такси» модальность по умолчанию отключена, и такой вызов выдаст ошибку. Для них есть асинхронные замены — о них следующий раздел.
Клиент или сервер: где появится сообщение
Код в 1С выполняется в двух контекстах, и от этого зависит, какой метод вообще доступен.
Доступны и на клиенте, и на сервере:
Сообщить()СообщениеПользователю
Только на клиенте (интерактивные методы):
Предупреждение(),Вопрос(), всеПоказать*ПоказатьОповещениеПользователя()Состояние()
Главная тонкость — поведение Сообщить() на сервере. Серверный вызов не может сам нарисовать окно на экране пользователя. Поэтому платформа складывает сообщения в буфер и отдаёт их клиенту целиком, когда серверная процедура закончит работу.
&НаСервере
Процедура ПроверитьНаСервере()
Сообщить("Строка 1"); // появится не сразу,
Сообщить("Строка 2"); // а когда вызов вернётся на клиент
КонецПроцедуры
Отсюда типичная путаница: разработчик ждёт сообщение в середине долгой серверной обработки, а оно выходит только в конце пачкой. Если нужно показать прогресс по ходу — это делается иначе, через фоновое задание и строку состояния на клиенте.
Вызвать на сервере Предупреждение() или Вопрос() нельзя в принципе: интерактивных методов там нет. Логика строится так — сервер считает и возвращает результат, а решение «спросить пользователя» принимает клиентская процедура.
То же касается модулей объектов. В обработчике ОбработкаПроведения или ОбработкаПроверкиЗаполнения вы на сервере — здесь работают Сообщить() и СообщениеПользователю, а диалоги недоступны. Привязка СообщениеПользователю к полю при этом сохраняется: платформа донесёт сообщение до формы, с которой запускали проведение, и подсветит нужный реквизит.
Асинхронный код и всплывающие оповещения
В управляемом приложении с отключённой модальностью диалоги показывают через асинхронные методы. Они не останавливают выполнение: окно открывается, код идёт дальше, а реакцию пользователя ловит отдельная процедура-обработчик.
&НаКлиенте
Процедура УдалитьДокумент(Команда)
Оповещение = Новый ОписаниеОповещения("ПослеВопроса", ЭтотОбъект);
ПоказатьВопрос(Оповещение, "Удалить документ?", РежимДиалогаВопрос.ДаНет);
КонецПроцедуры
&НаКлиенте
Процедура ПослеВопроса(Результат, Параметры) Экспорт
Если Результат = КодВозвратаДиалога.Да Тогда
// здесь продолжаем после ответа
КонецЕсли;
КонецПроцедуры
Схема одинаковая для всей группы: ПоказатьПредупреждение(), ПоказатьВопрос(), ПоказатьВводЗначения(), ПоказатьВводСтроки(), ПоказатьВводЧисла(), ПоказатьВводДаты(). Первым параметром идёт ОписаниеОповещения с именем процедуры, которая сработает после закрытия окна. Процедура-обработчик должна быть с ключевым словом Экспорт и принимать результат первым параметром.
Через второй параметр ОписаниеОповещения можно передать в обработчик дополнительные данные — например, ссылку на документ, который разбираем:
ДопДанные = Новый Структура("Ссылка", Объект.Ссылка);
Оповещение = Новый ОписаниеОповещения("ПослеВопроса", ЭтотОбъект, ДопДанные);
В обработчике они придут вторым аргументом Параметры. Это стандартный способ «дотащить» контекст до асинхронного продолжения, потому что между открытием окна и ответом пользователя код уже вышел из первой процедуры.
Отдельный, самый ненавязчивый способ — всплывающее оповещение в правом нижнем углу. Оно не требует клика и само исчезает:
ПоказатьОповещениеПользователя("Отчёт сформирован");
ПоказатьОповещениеПользователя(
"Проведено",
,
"Документ записан и проведён",
БиблиотекаКартинок.Успех);
Оповещения хороши для фоновых событий: «файл загружен», «обмен завершён». Для подтверждения опасного действия они не годятся — пользователь может их не заметить.
СообщениеПользователю с заполненными Поле и УстановитьДанные — клик по тексту переведёт курсор в реквизит.Сообщить() или СообщениеПользователю без поля. Это окно сообщений внизу формы.ПоказатьВопрос() с процедурой-обработчиком. Модальный Вопрос() — только если модальность в конфигурации разрешена.ПоказатьОповещениеПользователя() — всплывёт в углу и само пропадёт.ЗаписьЖурналаРегистрации() — текст уйдёт в журнал, а не на экран.Строка состояния и очистка окна сообщений
Строка состояния Состояние() выводит короткий текст в отдельной области и подходит для индикации хода работы.
Для Сч = 1 По Количество Цикл
Состояние("Обработано: " + Формат(Сч, "ЧГ=0") + " из " + Формат(Количество, "ЧГ=0"));
// ... обработка ...
КонецЦикла;
Состояние(); // убрать строку
Второй параметр принимает процент выполнения — платформа покажет полоску прогресса:
Состояние("Загрузка", Процент, "Идёт обмен данными");
Состояние() работает только на клиенте и показывает текст ровно в тот момент, когда его вызвали. Поэтому для длинной операции прогресс выносят в фоновое задание: сервер считает в фоне, а клиент периодически опрашивает его и обновляет строку состояния. В типовых конфигурациях для этого есть готовый механизм длительных операций с индикатором выполнения — изобретать свой цикл опроса обычно не нужно.
Окно сообщений очищают методом ОчиститьСообщения(). Его зовут перед новой проверкой, чтобы старые строки не смешивались с новыми.
ОчиститьСообщения();
// ... запускаем проверку заново ...
Частый приём в обработках проверки: в начале — ОчиститьСообщения(), затем цикл с СообщениеПользователю по каждой ошибке, а в конце — одно итоговое оповещение «Найдено ошибок: N».
Журнал регистрации вместо вывода на экран
Не каждое сообщение нужно показывать пользователю. Служебные события, диагностику обмена, перехваченные исключения логичнее писать в журнал регистрации — там запись сохранится с датой, именем пользователя и сеансом.
ЗаписьЖурналаРегистрации(
"Обмен.Загрузка",
УровеньЖурналаРегистрации.Ошибка,
,
,
"Не удалось разобрать файл: " + ОписаниеОшибки());
Первый параметр — имя события (произвольная строка, по ней потом фильтруют журнал), второй — уровень: Информация, Предупреждение, Ошибка. Последний параметр — текст. Журнал открывают через Главное → Все функции → Стандартные → Журнал регистрации (или из раздела администрирования) и фильтруют по имени события.
Запись в журнал не зависит от того, есть ли на экране пользователь, и доступна на сервере без ограничений. Поэтому в обменах, регламентных заданиях и обработчиках проведения ошибки пишут именно туда, а не в окно сообщений, которое в фоновом сеансе всё равно никто не увидит.
Для отладки по ходу разработки удобнее не плодить Сообщить(), а ставить точки останова в конфигураторе и смотреть значения в табло. Отладочные Сообщить() потом легко забыть в коде — и они полезут пользователю в рабочей базе.
Разница по назначению простая:
- 🧑💼 Пользователю прямо сейчас —
Сообщить,СообщениеПользователю, диалоги, оповещения. - 🗂 Для разбора потом —
ЗаписьЖурналаРегистрации. - 🐞 Себе при разработке — точки останова и табло отладчика.
Типичные ошибки при выводе сообщений
Несколько промахов, на которые уходит больше всего времени.
Вызов модального метода в управляемом приложении. Предупреждение() или Вопрос() падают с ошибкой об использовании модальных окон. Решение — асинхронные Показать* либо включение режима модальности в свойствах конфигурации (для нового кода так делать не стоит).
Ожидание серверного Сообщить() в реальном времени. Текст копится и выходит после возврата на клиент. Для построчного прогресса длинной операции используют фоновое задание.
Сообщение без привязки, хотя привязка нужна. Если не заполнить Поле и не вызвать УстановитьДанные, пользователь увидит «не заполнен контрагент», но не поймёт, в какой строке и форме. Для проверок заполнения всегда указывайте поле.
Склейка числа со строкой без форматирования. "Строк: " + Счётчик на дробном числе даст разделитель и лишние знаки. Оборачивайте в Формат(Счётчик, "ЧГ=0").
Отладочные Сообщить() в релизе. Перед выкладкой обработки в рабочую базу пройдитесь поиском по тексту Сообщить( и уберите временные строки.
Чем `СообщениеПользователю` лучше `Сообщить()`?
Сообщить() такой привязки нет, и сам метод помечен как устаревший.Почему `Предупреждение()` выдаёт ошибку?
ПоказатьПредупреждение() с процедурой-обработчиком.Можно ли показать окно вопроса из серверного кода?
Показать* доступны только на клиенте. Сервер должен вернуть данные на клиент, а уже клиентская процедура задаёт вопрос пользователю.Как вывести текст во всплывающем окошке в углу экрана?
ПоказатьОповещениеПользователя("Текст"). Оно появляется в правом нижнем углу и пропадает само, клик не требуется.Как убрать старые строки из окна сообщений?
ОчиститьСообщения() перед тем, как выводить новую порцию. Обычно это делают в начале процедуры проверки.