К статье
Практический материал

Разработка и Конфигурация · 11 мин

Как проверить, открыта ли форма в 1С

Способы проверить, открыта ли форма в 1С: Открыта(), УникальныйИдентификаторФормы, поиск по окнам. Примеры кода для тонкого и управляемого приложения.

Задача проверить, открыта ли форма, возникает в двух типовых сценариях: нужно избежать повторного открытия уже открытой формы (например, формы документа или обработки) или перед выполнением действия убедиться, что пользователь работает с конкретным окном. В 1С:Предприятии 8 для этого есть несколько механизмов, и выбор зависит от того, где выполняется код — внутри самой формы или снаружи, и от режима работы: управляемое приложение или обычные формы.

Ключевая сложность в том, что у управляемых форм нет глобального списка открытых окон, доступного напрямую из кода. Платформа намеренно изолирует формы друг от друга, поэтому «найти чужую форму» можно только через косвенные механизмы: уникальный идентификатор формы, оповещения, параметры открытия. Ниже разобраны рабочие способы с примерами кода и их ограничениями.

Важно сразу разделить две разные проверки. Первая — вызов метода Открыта() у объекта формы, когда у вас уже есть ссылка на эту форму. Вторая — определение факта открытия формы без ссылки на неё, например при попытке открыть форму повторно. Это разные задачи, и решаются они разными инструментами.

Проверка через метод Открыта(), когда ссылка на форму известна

Метод Открыта() доступен у объектов «УправляемаяФорма» и «Форма» (обычные формы). Он возвращает булево значение: Истина, если форма открыта и видима пользователю, и Ложь, если форма закрыта либо ещё не была открыта. Это самый прямой способ, но он требует, чтобы переменная со ссылкой на форму сохранялась между вызовами.

Типовой пример: обработка хранит ссылку на открытую форму настройки в реквизите или в переменной модуля. Перед повторным открытием код проверяет состояние формы и либо активирует существующую, либо создаёт новую.

bsl
Если ФормаНастройки <> Неопределено И ФормаНастройки.Открыта() Тогда
    ФормаНастройки.Активизировать();
Иначе
    ФормаНастройки = ПолучитьФорму("Обработка.МояОбработка.Форма.Настройки");
    ФормаНастройки.Открыть();
КонецЕсли;

Обратите внимание на порядок условия: сначала проверяется, что переменная не равна Неопределено, и только потом вызывается метод. Если вызвать Открыта() у неинициализированной переменной, будет ошибка выполнения. Проверка через И в одном условии безопасна, потому что встроенный язык вычисляет левую часть первой и не выполняет правую при ложном результате.

Метод Активизировать() выводит уже открытую форму на передний план. Это полезно, когда пользователь пытается открыть тот же объект повторно из меню или команды — вместо дублирования окна фокус просто переходит к существующему.

Ключ уникальности формы как защита от повторного открытия

В управляемом приложении платформа умеет сама предотвращать дублирование форм, если при открытии задан ключ уникальности. Ключ передаётся как параметр в методы ОткрытьФорму() и ПолучитьФорму(). Если форма с таким ключом уже открыта, платформа не создаст новый экземпляр, а вернёт или активирует существующий.

bsl
ПараметрыФормы = Новый Структура("Ключ", ДокументСсылка);
ОткрытьФорму("Документ.РеализацияТоваровУслуг.Форма.ФормаДокумента", ПараметрыФормы);

Для форм объектов (документов, справочников) ключом уникальности по умолчанию служит ссылка на объект: две формы одного и того же документа платформа не откроет. Но для произвольных форм — обработок, отчётов, форм настроек — ключ нужно задавать явно, иначе каждый вызов ОткрытьФорму() создаст новое окно.

В качестве ключа можно использовать строку, число, ссылку или уникальный идентификатор. Практичный приём — строить ключ из смысловых частей, например \"Настройки_\" + ИмяПользователя(), если настройки должны быть отдельными для каждого пользователя в одном сеансе.

Уникальный идентификатор формы и проверка её существования

У каждой открытой управляемой формы есть свойство УникальныйИдентификаторФормы — значение типа «УникальныйИдентификатор», которое платформа присваивает при создании. Если при открытии формы сохранить этот идентификатор (в параметре сеанса, реквизите формы-владельца или структуре на клиенте), позже по нему можно однозначно идентифицировать именно этот экземпляр формы.

Сам идентификатор не даёт метода «проверить, жива ли форма» напрямую. На практике проверку строят комбинированно: хранят идентификатор вместе со ссылкой на форму и при необходимости проверяют Открыта(). Если форма закрыта, сохранённый идентификатор очищают, чтобы следующая попытка открытия создала новый экземпляр.

Ещё одно применение идентификатора — владелец формы. При вызове ОткрытьФорму() можно передать параметр «Владелец», и тогда платформа связывает формы: закрытие владельца закроет и дочернюю форму. Это снимает часть задач ручного контроля за открытыми окнами.

Оповещения: реакция на закрытие формы вместо постоянной проверки

Вместо периодической проверки «открыта ли форма» в управляемом приложении правильнее использовать механизм оповещений. При открытии формы через ОткрытьФорму() можно передать описание оповещения о закрытии — процедуру, которая будет вызвана автоматически, когда пользователь закроет форму.

bsl
Оповещение = Новый ОписаниеОповещения("ПослеЗакрытияНастроек", ЭтотОбъект);
ОткрытьФорму("Обработка.МояОбработка.Форма.Настройки", , ЭтотОбъект, , , , Оповещение);

&НаКлиенте
Процедура ПослеЗакрытияНастроек(Результат, ДополнительныеПараметры) Экспорт
    ФормаНастройкиОткрыта = Ложь;
КонецПроцедуры

Дополнительно существует глобальный механизм Оповестить() и обработчик ОбработкаОповещения() у форм. Форма при открытии может оповестить другие окна о своём состоянии, а заинтересованные формы — отреагировать. Это стандартный способ обмена сообщениями между независимыми формами без прямых ссылок друг на друга.

Подход с оповещениями предпочтительнее циклических проверок: код не тратит ресурсы на опрос состояния, а реагирует на событие в момент его наступления. Это особенно важно в клиент-серверном режиме, где лишние серверные вызовы замедляют работу пользователей.

Типичные ошибки
01
Вызов Открыта() у переменной, равной Неопределено, — приводит к ошибке выполнения; сначала проверяйте саму ссылку.
02
Повторное открытие формы без ключа уникальности — создаются дубли окон, пользователь путается, а данные в формах расходятся.
03
Проверка открытости формы в цикле с задержкой вместо оповещения о закрытии — лишняя нагрузка и непредсказуемое поведение.
04
Попытка найти открытую форму другого пользователя через клиентские механизмы — такой возможности нет, нужны серверные средства.

Проверка в обычных формах и поиск по окнам

В обычном приложении (режим толстого клиента с обычными формами) возможностей больше: там доступна коллекция окон через ПолучитьОкна(), и можно перебрать открытые окна главного окна приложения, сравнивая заголовки или содержащиеся формы. Этот приём не работает в управляемом приложении и в веб-клиенте.

bsl
Окна = ПолучитьОкна();
Для Каждого Окно Из Окна Цикл
    Если Окно.Заголовок = "Настройки обмена" Тогда
        Окно.Активизировать();
        Прервать;
    КонецЕсли;
КонецЦикла;

Сравнение по заголовку ненадёжно: заголовок может меняться динамически, локализоваться или совпадать у разных форм. Если есть доступ к форме окна через Окно.ПолучитьСодержимое(), надёжнее сравнивать тип формы или её данные, а не текст заголовка.

При переносе кода из обычного приложения в управляемое такие конструкции перестают компилироваться или работать. Планируя миграцию, заменяйте поиск по окнам на ключи уникальности и оповещения заранее — это снимет целый класс ошибок при переходе.

Как выбрать подходящий способ

Выбор метода определяется тем, что известно в момент проверки, и режимом работы прикладного решения. Ниже — ориентиры для типовых ситуаций.

Маршрут решения

Как выбрать действие

Ссылка на форму хранится в переменной или реквизитеИспользуйте метод Открыта() с предварительной проверкой на Неопределено
Нужно запретить дубли формы при открытииПередавайте ключ уникальности в ОткрытьФорму() — платформа вернёт существующий экземпляр
Нужно узнать, когда форма закроетсяПередавайте описание оповещения о закрытии при открытии формы
Код работает в обычном приложенииДоступен перебор окон через ПолучитьОкна(), но сравнивайте формы, а не заголовки
Нужно проверить форму другого пользователяКлиентские методы не подходят — используйте серверные механизмы: блокировки, регистры состояний
СпособРежимКогда применятьОграничение
Метод Открыта()ЛюбойЕсть ссылка на формуБез ссылки не работает
Ключ уникальностиУправляемое приложениеПредотвращение дублей при открытииТолько в пределах сеанса
Оповещение о закрытииУправляемое приложениеРеакция на закрытие формыНе сообщает текущее состояние «здесь и сейчас»
ПолучитьОкна()Обычное приложениеПоиск окна среди открытыхНедоступно в управляемом режиме и веб-клиенте

Во всех случаях полезно проверять результат действием: после активации формы убедитесь визуально в тестовом сеансе, что фокус перешёл к нужному окну, а после закрытия — что флаг состояния сброшен и повторное открытие создаёт чистую форму, а не «висит» на старой ссылке.

Итог

Что важно запомнить

Прямой способ — метод Открыта() при наличии ссылки на форму. Для защиты от дублей используйте ключ уникальности в ОткрытьФорму(), а для реакции на закрытие — описание оповещения. Поиск по окнам доступен только в обычном приложении; проверить форму другого пользователя из клиентского кода нельзя.

Частые вопросы

Можно ли проверить, открыта ли форма, не имея на неё ссылки?

Напрямую в управляемом приложении — нет: глобального списка открытых форм из кода не существует. Обходные пути — задавать ключ уникальности при открытии (платформа сама найдёт существующий экземпляр), сохранять ссылку на форму при её создании или обмениваться состоянием через оповещения.

Чем ОткрытьФорму() отличается от ПолучитьФорму() при проверке?

ПолучитьФорму() создаёт форму и возвращает ссылку на неё, но не показывает пользователю — отображение выполняется отдельным вызовом Открыть(). ОткрытьФорму() делает всё сразу. Для проверки состояния удобнее ПолучитьФорму(), потому что вы получаете ссылку, которую можно сохранить и дальше использовать с методом Открыта().

Почему Открыта() возвращает Ложь, хотя окно видно на экране?

Чаще всего переменная ссылается на другой экземпляр формы: форму открыли повторно без ключа уникальности, и на экране новое окно, а в переменной — старое, уже закрытое. Проверьте, что форма не дублируется, и при открытии передавайте ключ уникальности.

Как узнать, что форму закрыл другой пользователь или система?

Клиентский код не видит формы других сеансов. Если нужен контроль на уровне базы, фиксируйте состояние на сервере: например, записывайте в регистр сведений факт открытия и закрытия через события формы ПриОткрытии и ПриЗакрытии, и читайте этот регистр там, где требуется проверка.

Работает ли метод Открыта() в веб-клиенте?

Да, метод Открыта() и механизм оповещений работают в веб-клиенте так же, как в тонком. Не работают только средства обычного приложения — ПолучитьОкна() и связанные с ним конструкции, поскольку обычные формы в веб-клиенте не поддерживаются.

Что делать, если форма «зависла» и Открыта() возвращает Истина, но окна нет?

Такое встречается при модальных блокировках или ошибках в обработчиках формы. Убедитесь, что форма не открыта модально и не перекрыта другим модальным окном. Если проблема воспроизводится, проверьте обработчики ПриОткрытии и ПриПовторномОткрытии на ошибки — исключение в них может оставить форму в неконсистентном состоянии.