ОчиститьСообщения() и не только: управляем сообщениями пользователю в 1С 8.3
Содержание
Программно очистить окно сообщений в 1С 8.3 можно одной строкой: вызовом процедуры глобального контекста ОчиститьСообщения(). Работает она только на клиенте — в модуле формы с директивой &НаКлиенте или в общем клиентском модуле. На сервере её нет, и это главная причина ошибок у тех, кто переносит код из старых обработок.
Частое заблуждение — что очистка удаляет «одно лишнее сообщение». Нет: платформа не даёт удалить отдельную строку из окна. Можно стереть всё разом или перехватить сообщения ещё до показа, отфильтровать и вывести только нужные. Оба приёма разобраны ниже, с кодом для управляемых форм, сервера и фоновых заданий.
Откуда берутся сообщения и где они хранятся
В 8.3 сообщение пользователю — это объект СообщениеПользователю. У него есть текст и свойства, которые привязывают сообщение к форме и полю. Старый метод Сообщить() по-прежнему работает, но внутри создаёт то же самое сообщение, только без привязки.
Основные свойства объекта:
- 📝
Текст— что увидит пользователь; - 🎯
Поле— имя реквизита или элемента, рядом с которым появится значок ошибки; - 🗂
ПутьКДанным— путь к данным формы, напримерОбъект; - 🔑
КлючДанных— ссылка на объект, к которому относится сообщение; - 🪟
ИдентификаторНазначения— уникальный идентификатор формы, в которой сообщение должно появиться.
Где сообщение окажется на экране, зависит от того, откуда его вызвали:
| Где создано сообщение | Куда попадает | Когда пользователь его видит |
|---|---|---|
| Клиентский код формы | Панель сообщений активной формы | Сразу |
| Серверный вызов из формы | Копится на сервере, уходит на клиент с ответом | После возврата с сервера |
| Фоновое задание | Копится внутри задания | Только если клиент сам их заберёт |
| Внешнее соединение (COM) | Окна нет, сообщения копятся в сеансе | Только через программное чтение |
| Обычное приложение, толстый клиент | Отдельное окно сообщений внизу главного окна | Сразу |
Отсюда вывод: «очистить сообщения» означает разные вещи в разных контекстах. На клиенте — стереть то, что уже показано. На сервере и в фоне — забрать накопленное, пока оно не дошло до экрана.
Как очистить все сообщения из кода
Процедура ОчиститьСообщения() на клиенте
Самый частый сценарий: перед проверкой заполнения формы убрать старые ошибки, чтобы пользователь видел только актуальные.
&НаКлиенте
Процедура Провести(Команда)
ОчиститьСообщения();
Если Не ПроверитьЗаполнение() Тогда
Возврат;
КонецЕсли;
ПровестиНаСервере();
КонецПроцедуры
Порядок здесь принципиален. Сначала очистка, потом проверка. Если поменять строки местами, очистка сотрёт только что выведенные ошибки, и пользователь не поймёт, почему документ не провёлся.
ОчиститьСообщения() не принимает параметров и ничего не возвращает. Вызывать её можно в любом клиентском обработчике: команды, события формы, обработчика ожидания.
Удаление накопленных сообщений через ПолучитьСообщенияПользователю
Функция глобального контекста ПолучитьСообщенияПользователю(УдалятьПолученные) возвращает фиксированный массив объектов СообщениеПользователю. Если передать Истина, полученные сообщения удаляются из буфера и на экран уже не попадут.
Это и есть способ «очистить» сообщения на сервере:
&НаСервере
Процедура ЗаполнитьНаСервере()
// Служебная процедура может насыпать лишних сообщений
ЗаполнитьТабличнуюЧасть();
// Забираем всё накопленное и удаляем из буфера
Сообщения = ПолучитьСообщенияПользователю(Истина);
КонецПроцедуры
Пользователь не увидит ни одного сообщения, созданного внутри ЗаполнитьТабличнуюЧасть() в этом серверном вызове. Пользуйтесь этим осознанно: вместе с мусором исчезнут и настоящие ошибки.
С параметром Ложь (значение по умолчанию) функция только читает сообщения, ничего не удаляя. Это удобно для логирования.
Фильтр: оставить нужные, убрать лишние
Раз удалить одно сообщение нельзя, его делают иначе: забирают всё, а нужное выводят заново.
&НаСервере
Процедура ВыполнитьСФильтромНаСервере()
ВыполнитьОбработку();
Накопленные = ПолучитьСообщенияПользователю(Истина);
Для Каждого Сообщение Из Накопленные Цикл
// Пропускаем технические строки
Если СтрНачинаетсяС(Сообщение.Текст, "[отладка]") Тогда
Продолжить;
КонецЕсли;
Сообщение.Сообщить();
КонецЦикла;
КонецПроцедуры
Каждый объект СообщениеПользователю сохраняет Поле, ПутьКДанным и КлючДанных. Поэтому повторный вызов Сообщить() вернёт значок ошибки к тому же реквизиту формы.
Строка состояния: что показывает Состояние() и как её убрать
Процедура Состояние() выводит не сообщение, а индикатор хода работы: текст, полосу прогресса и пояснение. В окно сообщений она ничего не пишет, поэтому ОчиститьСообщения() на неё не действует.
&НаКлиенте
Процедура ОбработатьСтроки(Команда)
Всего = Объект.Товары.Количество();
Номер = 0;
Для Каждого Строка Из Объект.Товары Цикл
Номер = Номер + 1;
Процент = Окр(Номер / Всего * 100);
Состояние(СтрШаблон("Обработано %1 из %2", Номер, Всего), Процент);
// ... обработка строки
КонецЦикла;
КонецПроцедуры
Как ведёт себя состояние в разных клиентах:
- 🖥 Тонкий и веб-клиент. Появляется всплывающее окно состояния, которое закрывается само через несколько секунд после последнего вызова. Специально убирать его обычно не нужно.
- 🧱 Толстый клиент, обычное приложение. Текст висит в строке состояния главного окна, пока его не заменят. Чтобы стереть, вызовите
Состояние()без параметров или с пустой строкой.
Если Состояние() вызывать в цикле на каждой итерации из тысяч строк, обработка заметно замедлится. Обновляйте индикатор раз в 50–100 строк: Если Номер % 100 = 0 Тогда Состояние(...) КонецЕсли;.
Есть ещё ПоказатьОповещениеПользователя() — всплывающее уведомление в углу экрана. Оно тоже не относится к окну сообщений и исчезает само.
Тонкий клиент, веб-клиент, толстый клиент и фон: в чём разница
Управляемые формы (тонкий и веб-клиент)
Каждая форма имеет свою панель сообщений внизу. Сообщения с заполненным ИдентификаторНазначения появляются именно в той форме, чей идентификатор указан. Без него сообщение уйдёт в текущую активную форму.
Чтобы серверное сообщение попало в нужную форму, а не туда, где сейчас курсор:
&НаСервере
Процедура ПроверитьНаСервере()
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Не указан контрагент";
Сообщение.Поле = "Контрагент";
Сообщение.УстановитьДанные(Объект);
Сообщение.ИдентификаторНазначения = УникальныйИдентификатор;
Сообщение.Сообщить();
КонецПроцедуры
Пользователь может и сам закрыть панель сообщений крестиком.
Толстый клиент в режиме обычного приложения
Здесь одно общее окно сообщений на всё приложение. ОчиститьСообщения() стирает его полностью. Вручную пользователь очищает его через контекстное меню окна правой кнопкой мыши.
Фоновые задания
Фоновое задание выполняется без интерфейса. Его сообщения не показываются никому, пока клиент их не заберёт методом объекта ФоновоеЗадание:
&НаСервереБезКонтекста
Функция СообщенияЗадания(ИдентификаторЗадания)
Задание = ФоновыеЗадания.НайтиПоУникальномуИдентификатору(ИдентификаторЗадания);
Если Задание = Неопределено Тогда
Возврат Новый Массив;
КонецЕсли;
Возврат Задание.ПолучитьСообщенияПользователю(Истина);
КонецФункции
Параметр Истина здесь важен. Без него при каждом опросе вы будете получать одни и те же сообщения повторно, и они начнут дублироваться на экране.
В типовых конфигурациях на БСП эту работу берёт на себя подсистема длительных операций. Если пишете доработку для типовой — пользуйтесь ею, а не собственным опросом.
Внешнее соединение
Через COM-соединение окна нет совсем. Сообщения, вызванные внутри базы, копятся в сеансе. Внешняя программа читает их через ПолучитьСообщенияПользователю(Истина) у объекта соединения — так их можно записать в лог интеграции, а не потерять.
Готовые шаблоны кода для типовых задач
Шаблон 1. Чистая проверка перед записью
&НаКлиенте
Процедура ПередЗаписью(Отказ, ПараметрыЗаписи)
ОчиститьСообщения();
Если Не ЗначениеЗаполнено(Объект.Контрагент) Тогда
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Заполните поле «Контрагент»";
Сообщение.Поле = "Объект.Контрагент";
Сообщение.Сообщить();
Отказ = Истина;
КонецЕсли;
КонецПроцедуры
Шаблон 2. Сбор сообщений в журнал вместо экрана
Пригодится для регламентных заданий и пакетных загрузок, где сотни однотипных предупреждений только мешают.
Процедура ЗаписатьСообщенияВЖурнал(ИмяСобытия)
Накопленные = ПолучитьСообщенияПользователю(Истина);
Для Каждого Сообщение Из Накопленные Цикл
ЗаписьЖурналаРегистрации(ИмяСобытия,
УровеньЖурналаРегистрации.Предупреждение, , ,
Сообщение.Текст);
КонецЦикла;
КонецПроцедуры
Сообщения уходят в журнал регистрации, их можно найти по имени события. С экрана они исчезают.
Шаблон 3. Счётчик вместо сотни строк
&НаСервере
Процедура ЗагрузитьНаСервере()
ЗагрузитьДанные();
Накопленные = ПолучитьСообщенияПользователю(Истина);
Если Накопленные.Количество() > 0 Тогда
Итог = Новый СообщениеПользователю;
Итог.Текст = СтрШаблон("Загрузка завершена, замечаний: %1. Подробности в журнале регистрации.",
Формат(Накопленные.Количество(), "ЧГ=0"));
Итог.Сообщить();
КонецЕсли;
КонецПроцедуры
Пользователь видит одну итоговую строку. Количество форматируется через Формат(..., "ЧГ=0"), чтобы 1500 не превратилось в «1 500» с неразрывным пробелом.
Шаблон 4. Очистка при открытии формы
Если форма открывается из другой формы, где только что были ошибки, имеет смысл начать с чистого листа:
&НаКлиенте
Процедура ПриОткрытии(Отказ)
ОчиститьСообщения();
КонецПроцедуры
Почему очистка не срабатывает: разбор ошибок
Как отлаживать, если причина не очевидна:
- Поставьте точку останова на строку
ОчиститьСообщения()и убедитесь, что отладчик в неё заходит. - Сразу после серверного вызова на клиенте посмотрите в отладчике результат
ПолучитьСообщенияПользователю(Ложь)— увидите, что именно пришло с сервера. - Проверьте, нет ли второго вызова очистки в обработчике
ПриАктивизацииСтрокиили в обработчике ожидания. Такие «скрытые» очистки стирают сообщения через доли секунды. - Если доработка сделана в расширении, проверьте, не вызывается ли типовой обработчик после вашего с собственной очисткой.
- Временно закомментируйте все вызовы
ОчиститьСообщения()в модуле формы и повторите действие. Если сообщения появились, ищите виновника среди этих вызовов по одному, возвращая их обратно.
Если сообщения не появились и без очистки, проблема не в ней. Значит, сообщение вообще не создаётся: условие проверки не выполняется, либо код стоит в ветке, куда выполнение не доходит. Тогда ставьте точку останова на сам вызов Сообщить().
Окно «Служебные сообщения» в Конфигураторе — это другое окно. Его не очищает ни один метод встроенного языка, только контекстное меню самого Конфигуратора.
Когда программная очистка сообщений вредит
Очистка выглядит безобидной, но в трёх ситуациях она прячет от пользователя то, что ему нужно увидеть.
1. Очистка в обработчике, который срабатывает часто. ПриАктивизацииСтроки, ПриИзменении реквизита, обработчик ожидания с интервалом в секунду. Пользователь провёл документ, получил список ошибок, щёлкнул по строке табличной части — и ошибки пропали. Исправлять теперь приходится по памяти.
2. Глухое удаление на сервере. Вызов ПолучитьСообщенияПользователю(Истина) без разбора удаляет и мусор, и предупреждения типового кода: о незаполненном счёте учёта, о нехватке остатков, о проблемах с правами. В типовой конфигурации после обновления в этот же серверный вызов могут добавиться новые проверки, и ваш код молча их «съест».
3. Очистка перед длительной операцией. Если бухгалтер запускает закрытие месяца или массовое перепроведение, а в окне висели замечания с прошлого запуска, они могут быть нужны для сравнения. Лучше выводить новую строку-разделитель с датой и временем запуска, чем стирать историю.
Практичное правило: очищайте только в начале действия, которое пользователь запустил сам, — команды, записи, проведения. В событиях, которые срабатывают «попутно», очистку не ставьте.
Если сообщений действительно слишком много, лучше переложить их в журнал регистрации (шаблон 2 выше) или свести к одной итоговой строке (шаблон 3). Пользователь сохранит возможность разобраться, а экран останется чистым.