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

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

Как в 1С узнать, какая форма открыта

Как в 1С определить, какая форма открыта: АктивноеОкно, ПолучитьОкна, УникальныйИдентификатор формы, перехват открытия. Примеры кода для управляемых и обычных форм.

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

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

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

Как получить активную форму через АктивноеОкно()

Метод АктивноеОкно() возвращает объект типа ОкноКлиентскогоПриложения, соответствующий окну, с которым пользователь работает в данный момент. Если активного окна нет (например, приложение свёрнуто или фокус у системного диалога), метод вернёт Неопределено — это нужно обязательно проверять перед обращением к свойствам.

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

&НаКлиенте

Процедура ПоказатьАктивнуюФорму(Команда)

Окно = АктивноеОкно();

Если Окно = Неопределено Тогда

Сообщить("Активное окно отсутствует");

Возврат;

КонецЕсли;

Форма = Окно.ПолучитьСодержимое();

Если Форма = Неопределено Тогда

Сообщить("В окне нет формы");

Возврат;

КонецЕсли;

Сообщить("Имя формы: " + Форма.ИмяФормы);

Сообщить("Заголовок окна: " + Окно.Заголовок);

КонецПроцедуры

Свойство ИмяФормы содержит полное имя формы в том виде, в каком оно передаётся в ОткрытьФорму(), например Справочник.Номенклатура.Форма.ФормаЭлемента. По этому имени удобно определять тип открытого объекта и принимать решение в логике обработки.

Как перебрать все открытые окна

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

Типичный сценарий — проверить, открыта ли форма определённого вида, чтобы не плодить дубликаты или чтобы передать в неё данные. Для этого в цикле сравнивается ИмяФормы содержимого каждого окна с искомым значением.

&НаКлиенте

Функция НайтиОткрытуюФорму(ИскомоеИмяФормы)

Окна = ПолучитьОкна();

Для Каждого Окно Из Окна Цикл

Форма = Окно.ПолучитьСодержимое();

Если Форма <> Неопределено

И Форма.ИмяФормы = ИскомоеИмяФормы Тогда

Возврат Форма;

КонецЕсли;

КонецЦикла;

Возврат Неопределено;

КонецФункции

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

Идентификация конкретной формы по УникальныйИдентификатор

Каждая управляемая форма при создании получает свойство УникальныйИдентификатор — значение типа УникальныйИдентификатор, неповторимое в рамках сеанса. Именно оно позволяет отличить одну форму элемента от другой, когда открыто несколько однотипных окон.

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

&НаКлиенте

Процедура ОткрытьИлиАктивировать(Команда)

ИскомыйИД = "a1b2c3d4-..."; // сохранённый ранее идентификатор

Окна = ПолучитьОкна();

Для Каждого Окно Из Окна Цикл

Форма = Окно.ПолучитьСодержимое();

Если Форма <> Неопределено

И Строка(Форма.УникальныйИдентификатор) = ИскомыйИД Тогда

Окно.Активизировать();

Возврат;

КонецЕсли;

КонецЦикла;

// Форма не найдена — открываем заново

ОткрытьФорму("Справочник.Номенклатура.Форма.ФормаЭлемента");

КонецПроцедуры

Сравнивать идентификаторы надёжнее через приведение к строке, поскольку значения, полученные в разное время, могут быть разными объектами с одинаковым содержимым. Хранить идентификатор между вызовами в управляемом приложении удобно в реквизите формы или в параметрах клиентского модуля.

Предотвращение дублей через КлючУникальности

Часто задача «узнать, открыта ли форма» на самом деле означает «не дать открыть её второй раз». Для этого не нужно вручную перебирать окна — платформа делает это сама, если при вызове ОткрытьФорму() передать параметр КлючУникальности.

Если форма с таким ключом уже открыта, платформа не создаст новый экземпляр, а активирует существующий. Ключом может быть строка, число, ссылка или уникальный идентификатор. Для форм объектов платформа по умолчанию использует ссылку на объект в качестве ключа, поэтому одна и та же накладная не откроется дважды — а вот для произвольных форм и обработок ключ нужно задавать явно.

&НаКлиенте

Процедура ОткрытьНастройки(Команда)

// Повторный вызов активирует уже открытую форму

ОткрытьФорму("Обработка.НастройкиОбмена.Форма.ФормаНастроек",

, , , , , , "ЕдинственныйЭкземпляр");

КонецПроцедуры

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

Порядок действий
  1. 1
    Определите, что именно нужно: активная форма, список всех форм или защита от дублей
  2. 2
    Для активной формы используйте АктивноеОкно().ПолучитьСодержимое() с проверкой на Неопределено
  3. 3
    Для поиска по всем окнам переберите ПолучитьОкна() и сравните ИмяФормы или УникальныйИдентификатор
  4. 4
    Для защиты от дублей передайте КлючУникальности в ОткрытьФорму()
  5. 5
    Проверьте результат: повторный вызов должен активировать существующее окно, а не создавать новое

Различия для обычных форм и толстого клиента

В обычном приложении (режим запуска «Обычное приложение», типичный для конфигураций на платформе 8.2 и ранних) модель окон другая. Там доступны глобальные свойства и методы обычных форм, а активную форму часто получают через АктивноеОкно() аналогично, но содержимое будет объектом типа Форма со своим набором свойств — у неё нет ИмяФормы в том же виде, ориентироваться приходится на заголовок или на метод ЭтотОбъект.Метаданные() внутри самой формы.

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

Сравнение вариантов

АктивноеОкно()

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

ПолучитьОкна()

Даёт полный список окон сеанса для поиска нужной формы. Требует перебора и сравнения по имени или идентификатору.

КлючУникальности

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

Оповестить() и обработчики

Подходит для обмена данными между открытыми формами без их поиска — формы сами реагируют на оповещения.

Отслеживание открытия форм через оповещения

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

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

Частые ошибки и как их избежать

Самая распространённая ошибка — обращение к Окно.ПолучитьСодержимое() без проверки, что окно вообще существует. Второе место занимает сравнение форм по заголовку: заголовок меняется в зависимости от данных объекта и локализации, поэтому для идентификации используйте только ИмяФормы или УникальныйИдентификатор.

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

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

Как проверить, что код работает правильно

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

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

Контрольные точки

Как проверить результат

Повторный вызов ОткрытьФорму с КлючУникальности
Норма

Активируется существующее окно, новый экземпляр не создаётся

Тревожный признак

Открывается вторая копия формы — ключ не передан или отличается

Поиск формы после её закрытия
Норма

Функция возвращает Неопределено

Тревожный признак

Возвращается ссылка на «мёртвую» форму — проверяйте актуальность в цикле

Вызов при отсутствии активного окна
Норма

Код обрабатывает Неопределено без ошибки

Тревожный признак

Исключение «Обращение к свойству Неопределено»

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

Можно ли узнать, какие формы открыты у другого пользователя?

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

Почему АктивноеОкно() возвращает Неопределено?

Так происходит, когда у клиентского приложения нет активного окна: программа свёрнута, фокус у системного диалога или код выполняется в момент, когда окно ещё не создано (например, в обработчике ПриНачалеРаботыСистемы до открытия начальной страницы). Всегда проверяйте результат перед обращением к ПолучитьСодержимое().

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

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

Работает ли ПолучитьОкна() в веб-клиенте?

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

Чем заменить поиск формы для передачи в неё данных?

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

Как запретить открытие второй копии внешней обработки?

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

Итог

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

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