В процессе разработки на платформе 1С:Предприятие 8.3 (особенно в режиме управляемого приложения) часто возникает необходимость программного взаимодействия с окном сообщений пользователю. Типичная задача — скопировать содержимое этого окна в буфер обмена или передать текст ошибок в другую форму. Однако штатные средства платформы накладывают определенные ограничения. В этой статье мы подробно разберем, как устроено окно сообщений, почему нельзя просто «установить на него фокус» и какими способами можно решить задачу получения текстов сообщений.
Для начала проанализируем, как работает механизм вывода сообщений. В управляемом приложении панель сообщений не является полноценным элементом управления, к которому можно обратиться по имени через ЭтаФорма.Элементы. Это системная область, которая динамически привязывается к активному окну или форме. Поскольку у этого элемента нет программного идентификатора в объектной модели встроенного языка, мы не можем вызвать метод УстановитьФокус() для списка сообщений.
Важно понимать, что сообщения могут выводиться в разные контексты. Если сообщение привязано к конкретному реквизиту формы, оно будет отображаться рядом с ним. Если сообщение «общее», оно попадает в нижнюю панель. Эта разрозненность делает задачу универсального захвата фокуса практически невыполнимой штатными методами.
Если наша конечная цель — скопировать сообщения, то нам не обязательно устанавливать фокус ввода. Мы можем перехватить сообщения до того, как они будут окончательно «забыты» платформой в очереди вывода. Рассмотрим, как правильно использовать метод ПолучитьСообщенияПользователю().
Этот метод позволяет извлечь накопленные сообщения из стека. Рассмотрим нюанс использования параметра очистки:
ПолучитьСообщенияПользователю(Истина), сообщения будут удалены из внутренней очереди и пользователь их вообще не увидит в стандартном окне.ПолучитьСообщенияПользователю(Ложь), мы получим массив объектов СообщениеПользователю, но при этом платформа все равно выведет их на экран в обычном режиме.Посмотрим на пример кода, который собирает все текущие сообщения в одну строку для последующего анализа или копирования:
// Пример получения текстов сообщений без их удаления с экрана
МассивСообщений = ПолучитьСообщенияПользователю(Ложь);
ТекстВсехСообщений = "";
Для Каждого ТекущееСообщение Из МассивСообщений Цикл
ТекстВсехСообщений = ТекстВсехСообщений + ТекущееСообщение.Текст + Символы.ПС;
КонецЦикла;
// Теперь переменную ТекстВсехСообщений можно передать в буфер или другую форму
Часто задача стоит иначе: нужно передать сообщения из модального или блокирующего окна в родительскую форму. В этом случае мы можем не пытаться «вытащить» данные из системного окна, а организовать собственный канал передачи данных. Разберем ситуацию, когда код, выводящий сообщения, нам неподвластен.
Проанализируем стратегию использования метода Оповестить(). В закрывающейся форме (например, в обработчике ПередЗакрытием) мы можем собрать сообщения и отправить их глобально по всей системе:
&НаКлиенте
Процедура ПередЗакрытием(Отказ, ЗавершениеРаботы, ТекстПравки, СтандартнаяОбработка)
// Собираем сообщения перед тем, как окно закроется
МассивСообщений = ПолучитьСообщенияПользователю(Истина);
ОбщийТекстОшибок = "";
Для Каждого Стр Из МассивСообщений Цикл
ОбщийТекстОшибок = ОбщийТекстОшибок + Стр.Текст + Chars.LF;
КонецЦикла;
Если ЗначениеЗаполнено(ОбщийТекстОшибок) Тогда
// Отправляем оповещение всем открытым формам
Оповестить("ПередачаСообщенийОбОшибках", ОбщийТекстОшибок, ЭтаФорма);
КонецЕсли;
КонецПроцедуры
В родительской форме нам достаточно прописать обработчик ОбработкаОповещения, который примет этот текст и выведет его повторно или запишет в лог.
Если все же необходимо именно визуально перевести фокус в окно сообщений (например, для интерактивной работы пользователя), мы можем прибегнуть к эмуляции горячих клавиш. В платформе 1С для активации панели сообщений используется комбинация Ctrl + Alt + O (в латинской раскладке).
Рассмотрим, как это реализовать через объект WScript.Shell. Этот метод будет работать только в операционной системе Windows и при наличии соответствующих прав доступа.
&НаКлиенте
Процедура АктивироватьОкноСообщений()
Попытка
Шелл = Новый COMОбъект("WScript.Shell");
// Эмуляция нажатия Ctrl+Alt+O
// ^ - Ctrl, % - Alt
Шелл.SendKeys("^%o");
Исключение
Сообщить("Не удалось эмулировать нажатие клавиш: " + ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры
Важно: Этот метод крайне нестабилен, так как результат зависит от того, какое приложение находится в фокусе в момент выполнения кода. Мы рекомендуем использовать его только в крайних случаях.
Для современных конфигураций на базе платформы 8.3.15 и выше самым элегантным решением будет использование расширения. Мы можем применить механизм &Вместо или &После к методу Сообщить() (если он обернут в общие модули) или перехватывать создание объектов СообщениеПользователю.
Разберем логику: создаем в расширении глобальную переменную (например, в общем модуле), которая будет накапливать все выведенные тексты. Это позволит в любой момент времени получить доступ к полной истории сообщений сеанса без необходимости взаимодействия с UI-элементами.
Выясним причину странного поведения сообщений при закрытии форм. Как показывает практика, если форма открыта в режиме БлокироватьОкноВладельца, сообщения могут «пропадать» или выводиться с задержкой, срабатывая после закрытия формы. Проанализируем ситуацию: это происходит из-за внутренней очереди событий платформы. Если переключить режим блокировки на БлокироватьВесьИнтерфейс, приоритет обработки очереди сообщений меняется, и они гарантированно отображаются в контексте активного окна. Это полезно учитывать при проектировании длительных процедур, выводящих протокол выполнения на экран.
Подводя итог, можно сказать, что прямого управления фокусом окна сообщений в 1С не предусмотрено «по дизайну». Однако, комбинируя методы перехвата данных и программную эмуляцию, мы можем добиться нужного результата:
ПолучитьСообщенияПользователю(Ложь).Оповестить().SendKeys.Рассмотренные подходы позволяют обойти ограничения платформы и сделать работу пользователя с сообщениями более удобной и автоматизированной.