В типовой платформе 1С:Предприятие 7.7 отсутствуют штатные механизмы для управления открытыми окнами вне текущего активного контекста. При разработке нестандартных решений или автоматизации интерфейса часто возникает потребность программно найти определенную форму по ее заголовку и закрыть её (например, если при выборе элемента справочника открывается лишнее окно или зависает интерфейс). Для решения этой задачи используется внешняя компонента FormEx и её объект Сервис.
Разберем подробно, как устроен механизм работы со списком окон в FormEx, какие методы для этого используются и как избежать типичных ошибок при закрытии окон в цикле.
Для управления формами компонента FormEx предоставляет объект Сервис, содержащий следующие ключевые методы:
СписокВсехОткрытыхОкон() — возвращает объект типа СписокЗначений. Значениями элементов этого списка являются контексты открытых форм, а их строковыми представлениями — системные заголовки окон.АктивныйКонтекст(Контекст) — определяет текущее активное окно. Метод принимает переменную по ссылке, в которую помещается контекст активной формы, и возвращает 1 в случае успеха или 0, если активного/контекстного окна нет.Посмотрим на базовый пример получения активного окна и его закрытия:
Процедура ЗакрытьАктивноеОкно()
Перем Конт;
Сервис = СоздатьОбъект("Сервис");
Если Сервис.АктивныйКонтекст(Конт) = 1 Тогда
Конт.Форма.Закрыть(0);
Иначе
Сообщить("Активное окно не является контекстным или нет активного окна.");
КонецЕсли;
КонецПроцедуры
Рассмотрим задачу, когда нам необходимо закрыть все открытые окна в сеансе пользователя, кроме того, из которого в данный момент выполняется вызов процедуры. Для этого мы сначала сохраняем контекст текущего окна, затем получаем полный список открытых окон и перебираем их.
Процедура ЗакрытьВсеНеактивныеОкна()
Перем КонтТекущегоОкна, Сервис, СЗ, РС, Индекс, Конт;
Сервис = СоздатьОбъект("Сервис");
КонтТекущегоОкна = "";
Сервис.АктивныйКонтекст(КонтТекущегоОкна);
СЗ = Сервис.СписокВсехОткрытыхОкон();
РС = СЗ.РазмерСписка();
Для Индекс = 1 По РС Цикл
Конт = СЗ.ПолучитьЗначение(Индекс);
// Пропускаем форму, из которой вызван код
Если Конт = КонтТекущегоОкна Тогда
Продолжить;
КонецЕсли;
// Закрываем неактивную форму без запроса сохранения
Конт.Форма.Закрыть(0);
КонецЦикла;
КонецПроцедуры
Выясним причину, почему прямой перебор коллекции с закрытием форм может вести себя некорректно. Когда мы закрываем окно методом Форма.Закрыть(0), внутренний список открытых окон платформы перестраивается. Чтобы безопасно обработать заголовки и закрыть только те окна, название которых содержит определенную подстроку, используем извлечение строкового представления через метод ПолучитьЗначение().
Разберем реализацию поиска окна по фрагменту заголовка:
Процедура ЗакрытьОкноПоЗаголовку(ИмяОкнаДляПоиска)
Перем Сервис, Окна, РС, Индекс, КонтФормы, ЗаголовокОкна;
Сервис = СоздатьОбъект("Сервис");
Окна = Сервис.СписокВсехОткрытыхОкон();
РС = Окна.РазмерСписка();
Если РС = 0 Тогда
Возврат;
КонецЕсли;
// Перебираем окна с конца к началу для безопасного закрытия
Для Индекс = -РС По -1 Цикл
ЗаголовокОкна = "";
КонтФормы = Окна.ПолучитьЗначение(-Индекс, ЗаголовокОкна);
// Проверяем соответствие заголовка окна
Если Найти(ВРег(СокрЛП(ЗаголовокОкна)), ВРег(СокрЛП(ИмяОкнаДляПоиска))) > 0 Тогда
Если ТипЗначенияСтр(КонтФормы) = "ГрупповойКонтекст" Тогда
КонтФормы.Форма.Закрыть(0);
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Проанализируем практические ситуации, с которыми можно столкнуться при использовании данного подхода:
Для Индекс = -РС По -1): при закрытии окна список активных дескрипторов меняется. Обход списка с конца к началу исключает смещение индексов еще не обработанных окон.ПриВыбореСтроки: если в форме списка справочника прописано жесткое открытие формы элемента (ОткрытьФорму(ТекущийЭлемент())), то в режиме выбора открываются одновременно две формы. Попытка закрыть окно непосредственно в момент его инициализации (например, через вызов формулы реквизита на форме) может привести к блокировке родительского окна.РасширениеФормы из состава FormEx, связывая его с контекстом окна через РасшФ.УстановитьФорму(КонтФормы.Форма).