Многие разработчики, переходящие с платформы 1С 7.7 или использующие обычные формы 1С 8.2, сталкиваются с неприятной особенностью управляемого приложения: системное окно, вызываемое методом Сообщить(), перестает автоматически прокручиваться вниз при накоплении большого количества строк. В результате пользователь видит только начало лога, а самые актуальные сообщения остаются «за кадром», что критично для длительных процессов обработки данных. Разберем подробно, почему это происходит и как реализовать удобный, прокручиваемый лог своими силами.
Проанализируем ситуацию с точки зрения архитектуры. В управляемом приложении (тонкий и веб-клиент) окно сообщений — это не просто область экрана, а отдельный элемент интерфейса, работающий в асинхронном режиме. Платформа намеренно накладывает ограничения на вывод: если сообщений становится слишком много, они группируются, а при превышении видимой области в нижней части окна появляется многоточие. Автоматическая прокрутка к последней строке не предусмотрена стандартными настройками Платформа, так как это может мешать пользователю работать с основной формой.
Более того, если код выполняется в длительном цикле на клиенте, интерфейсный поток может «замирать», не успевая отрисовывать изменения в окне сообщений до завершения всей процедуры. Рассмотрим, какие инструменты помогут нам обойти эти ограничения.
Это наиболее популярный и простой способ создания собственного лога. Мы добавим на форму реквизит с типом ТекстовыйДокумент и выведем его на форму как ПолеТекстовогоДокумента. Чтобы текст всегда прокручивался вниз, воспользуемся методом установки границ выделения.
Разберем по шагам реализацию этого метода:
ЛогСобытий (тип: ТекстовыйДокумент).Посмотрим на пример кода:
&НаКлиенте
Процедура ДобавитьСообщениеВЛог(ТекстСообщения)
// Добавляем новую строку в текстовый документ
ЛогСобытий.ДобавитьСтроку(Строка(ТекущаяДата()) + ": " + ТекстСообщения);
// Получаем количество строк для определения конца документа
КоличествоСтрок = ЛогСобытий.КоличествоСтрок();
// Программная прокрутка: устанавливаем курсор на последнюю строку
// Это заставляет интерфейс отобразить нижнюю часть документа
Элементы.ЛогСобытий.УстановитьГраницыВыделения(КоличествоСтрок + 1, 1, КоличествоСтрок + 1, 1);
КонецПроцедуры
Важный нюанс: Чтобы пользователь видел обновление лога прямо во время выполнения цикла (а не в самом конце), необходимо вызывать ОбработкаПрерыванияПользователя() или, в крайнем случае, ОбновитьОтображениеДанных(). Однако помните, что частое обновление формы существенно замедляет работу алгоритма.
Если процесс очень длительный (тысячи строк), хранение всего лога в текстовом поле может перегрузить память клиента. В этом случае применим стратегию «очереди», где мы храним только последние N сообщений. Проанализируем пример, предложенный участниками форума:
&НаКлиенте
Процедура ВывестиСообщениеСУдалениемСтарых(Текст, СписокЛога)
МаксимальныйРазмер = 50; // Храним только последние 50 строк
СписокЛога.Добавить(Текст);
Пока СписокЛога.Количество() > МаксимальныйРазмер Цикл
СписокЛога.Удалить(0); // Удаляем самую старую строку
КонецЦикла;
// Очищаем стандартное окно и выводим обновленный список
ОчиститьСообщения();
Для Каждого Стр Из СписокЛога Цикл
Сообщить(Стр.Значение);
КонецЦикла;
КонецПроцедуры
Этот метод позволяет поддерживать окно сообщений в «чистом» виде, отображая только актуальную информацию, однако он постоянно вызывает ОчиститьСообщения(), что может привести к мерцанию интерфейса.
Выясним причину, почему сообщения с сервера часто приходят «пачкой» в конце. Это происходит из-за того, что серверная процедура блокирует клиент до завершения работы. Правильный методологический подход заключается в запуске тяжелой задачи как ФоновоеЗадание.
Рассмотрим алгоритм реализации:
ФоновыеЗадания.Выполнить().ПодключитьОбработчикОжидания() с интервалом 1–2 секунды.ПолучитьСообщенияПользователю(Истина).Параметр Истина критически важен: он очищает буфер на сервере, возвращая только те сообщения, которые появились с момента последней проверки. Полученные строки мы можем добавлять в наше кастомное поле лога. Это обеспечит плавную работу интерфейса и реальную многопоточность: сервер считает, клиент показывает.
Если стандартного оформления недостаточно, можно использовать ПолеHTMLДокумента. Это позволит не только выделять ошибки красным цветом, но и использовать JavaScript для мгновенной прокрутки.
Проанализируем пример формирования HTML-строки:
&НаКлиенте
Процедура ОбновитьHTMLLog(НовоеСообщение)
// Добавляем текст и скрипт автопрокрутки вниз
JSСкрипт = "<script>window.scrollTo(0, document.body.scrollHeight);</script>";
ТекстHTML = ТекстHTML + "<p>" + НовоеСообщение + "</p>" + JSСкрипт;
КонецПроцедуры
При обновлении содержимого поля HTML браузерный движок внутри 1С исполнит скрипт window.scrollTo, и страница автоматически «упадет» в самый низ. Это наиболее эстетичный вариант, который очень нравится пользователям.
В завершение разберем несколько советов, которые помогут избежать падения производительности:
ЗаписьЖурналаРегистрации(). Окно сообщений — это инструмент для оперативного информирования пользователя, а не место для хранения истории за 12 часов работы.Состояние(). Он выводит текст в нижнюю панель платформы и работает значительно быстрее, чем Сообщить(), хотя и не хранит историю сообщений.Таким образом, хотя штатное окно Сообщить() в управляемых формах и не поддерживает автопрокрутку, платформа предоставляет достаточно инструментов (ТекстовыйДокумент, ФоновыеЗадания, HTML), чтобы реализовать полноценный и удобный механизм мониторинга длительных операций.