Открытие формы объекта в 1С: методы, параметры и события

· 9 мин

Содержание

Чтобы программно открыть форму объекта в управляемом приложении 1С 8.3, используют глобальный метод ОткрытьФорму. Первым параметром передают полное имя формы — например, "Справочник.Номенклатура.ФормаОбъекта", вторым — структуру параметров, где ключ Ключ указывает, какой именно элемент открыть.

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

Весь код ниже — для управляемого приложения 1С:Предприятие 8.3 (интерфейс «Такси»). В обычном приложении и в версии 8.2 механизм форм другой.

Базовое открытие: метод ОткрытьФорму

Главный инструмент — глобальная функция ОткрытьФорму. Она доступна только на клиенте. Полный синтаксис:

ОткрытьФорму(ИмяФормы, ПараметрыФормы, Владелец, Уникальность,
    Окно, НавигационнаяСсылка, ОписаниеОповещенияОЗакрытии, РежимОткрытияОкна)

Обязателен только первый параметр. Имя формы собирается из типа объекта, его имени в конфигурации и имени формы:

  • "Справочник.Контрагенты.ФормаОбъекта" — карточка элемента справочника;
  • "Документ.РеализацияТоваровУслуг.ФормаДокумента" — форма документа;
  • "Справочник.Номенклатура.ФормаСписка" — список;
  • "Справочник.Номенклатура.ФормаВыбора" — форма выбора;
  • "Обработка.ЗагрузкаДанных.Форма.НастройкаЗагрузки" — произвольная форма обработки (после слова Форма идёт её имя).

Чтобы открыть карточку существующего объекта, передаём его ссылку через стандартный параметр Ключ:

&НаКлиенте
Процедура ОткрытьКарточку(СсылкаНаЭлемент)
    ПараметрыФормы = Новый Структура("Ключ", СсылкаНаЭлемент);
    ОткрытьФорму("Справочник.Номенклатура.ФормаОбъекта", ПараметрыФормы);
КонецПроцедуры

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

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

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

&НаКлиенте
Процедура ОткрытьВыделенное(Команда)
    ТекущаяСтрока = Элементы.Список.ТекущаяСтрока;
    Если ТекущаяСтрока <> Неопределено Тогда
        ПараметрыФормы = Новый Структура("Ключ", ТекущаяСтрока);
        ОткрытьФорму("Справочник.Номенклатура.ФормаОбъекта", ПараметрыФормы);
    КонецЕсли;
КонецПроцедуры

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

Передача параметров и создание нового объекта

Второй параметр ОткрытьФорму — структура, через которую в форму передают данные. Кроме Ключ, платформа понимает ещё несколько стандартных параметров формы объекта:

ПараметрЧто делает
КлючОткрыть существующий объект по ссылке
ЗначениеКопированияСоздать новый объект копированием указанного
ОснованиеДляЗаполненияСоздать документ на основании другого объекта
ЗначениеЗаполненияЗаполнить реквизиты нового объекта значениями из структуры

Пример: создать новый элемент и сразу подставить группу-родителя.

&НаКлиенте
Процедура ДобавитьВГруппу(ГруппаСсылка)
    Заполнение = Новый Структура("Родитель", ГруппаСсылка);
    ПараметрыФормы = Новый Структура("ЗначениеЗаполнения", Заполнение);
    ОткрытьФорму("Справочник.Номенклатура.ФормаОбъекта", ПараметрыФормы);
КонецПроцедуры

В саму форму можно передавать и собственные параметры — любые ключи структуры. Прочитать их внутри формы нужно в обработчике ПриСозданииНаСервере:

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    Если Параметры.Свойство("ОткрытьТолькоДляПросмотра")
        И Параметры.ОткрытьТолькоДляПросмотра Тогда
        ТолькоПросмотр = Истина;
    КонецЕсли;
КонецПроцедуры

Собственные параметры доступны только в ПриСозданииНаСервере. Если параметр нужен на протяжении всей жизни формы, объявите его в палитре свойств формы с признаком «Всегда использовать» — иначе после создания формы он обнулится, и обратиться к нему позже не получится.

Открытие формы по ссылке без знания её имени

Когда на руках есть ссылка, а точное имя формы знать не хочется, подойдёт метод ПоказатьЗначение:

&НаКлиенте
Процедура ПоказатьЭлемент(Ссылка)
    ПоказатьЗначение(, Ссылка);
КонецПроцедуры

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

Минус в том, что вы не управляете, какая именно форма откроется, и не передаёте в неё дополнительные параметры. Для тонкой настройки возвращайтесь к ОткрытьФорму с явным именем.

Немодальный режим и обработка результата

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

Правильный подход — открыть форму немодально и получить результат через механизм оповещений. За это отвечает параметр ОписаниеОповещенияОЗакрытии:

&НаКлиенте
Процедура ВыбратьКонтрагента()
    Оповещение = Новый ОписаниеОповещения("ПослеВыбораКонтрагента", ЭтотОбъект);
    ОткрытьФорму("Справочник.Контрагенты.ФормаВыбора", , ЭтотОбъект,
        , , , Оповещение);
КонецПроцедуры

&НаКлиенте
Процедура ПослеВыбораКонтрагента(Результат, ДополнительныеПараметры) Экспорт
    Если Результат <> Неопределено Тогда
        Объект.Контрагент = Результат;
    КонецЕсли;
КонецПроцедуры

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

Если открытое окно должно блокировать работу с окном-владельцем (псевдомодальность), задайте последний параметр:

ОткрытьФорму("Обработка.Настройки.Форма.Диалог", , ЭтотОбъект,
    , , , Оповещение, РежимОткрытияОкнаФормы.БлокироватьОкноВладельца);

Значения режима:

  • Независимый — обычное окно, с остальными можно работать (по умолчанию);
  • БлокироватьОкноВладельца — блокируется только окно, из которого открыли;
  • БлокироватьВесьИнтерфейс — блокируется всё приложение, аналог старой модальности.

Какой способ открытия формы выбрать?

Прямое обращение к экземпляру формы

Внутри модуля формы на текущую форму ссылаются через ЭтотОбъект. Через него доступны все реквизиты, коллекция элементов и методы:

  • Объект — основной реквизит формы объекта (сам справочник или документ со всеми полями);
  • Элементы — коллекция элементов формы: поля, кнопки, таблицы, группы;
  • Модифицированность — признак, что данные формы изменены и не записаны;
  • ТолькоПросмотр — запрет на редактирование.

Типичная задача — программно поменять видимость или доступность поля:

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    Элементы.СуммаНДС.Видимость = Объект.УчитыватьНДС;
    Элементы.Комментарий.ТолькоПросмотр = ТолькоПросмотр;
КонецПроцедуры

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

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

&НаКлиенте
Процедура ПодготовитьИОткрыть()
    ПараметрыФормы = Новый Структура("Ключ", ТекущийЭлемент);
    Форма = ПолучитьФорму("Справочник.Номенклатура.ФормаОбъекта", ПараметрыФормы);
    Форма.ТолькоПросмотр = Истина;
    Форма.Открыть();
КонецПроцедуры

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

Повторное открытие и активация уже открытой формы

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

Самый надёжный ключ уникальности для карточки объекта — его ссылка:

&НаКлиенте
Процедура ОткрытьБезДублей(Ссылка)
    ПараметрыФормы = Новый Структура("Ключ", Ссылка);
    ОткрытьФорму("Справочник.Номенклатура.ФормаОбъекта", ПараметрыФормы,
        , Ссылка);
КонецПроцедуры

Повторный вызов с той же ссылкой не создаст второе окно, а выведет на передний план уже открытое. Именно так ведут себя списки: двойной клик по строке, которая уже открыта в карточке, просто активирует её окно.

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

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

// в форме объекта после записи
ОповеститьОбИзменении(Тип("СправочникСсылка.Номенклатура"));

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

События формы и корректное закрытие

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

  1. ПриСозданииНаСервере(Отказ, СтандартнаяОбработка) — форма создаётся, данные ещё не на клиенте. Здесь читают параметры и настраивают элементы.
  2. ПриОткрытии(Отказ) — клиентское событие перед показом окна. Параметр Отказ = Истина отменяет открытие.
  3. ПередЗакрытием(Отказ, ЗавершениеРаботы, ТекстПредупреждения, СтандартнаяОбработка) — можно задержать закрытие, если есть несохранённые данные.
  4. ПриЗакрытии(ЗавершениеРаботы) — окно уже закрывается, последний шанс что-то записать в настройки.

Закрывают форму методом Закрыть. Если передать аргумент, он попадёт в обработчик оповещения о закрытии у того, кто форму открыл:

&НаКлиенте
Процедура ВыбратьИЗакрыть()
    Закрыть(ТекущийВыбор);
КонецПроцедуры

Для форм выбора есть специализированный метод ОповеститьОВыборе(РезультатВыбора) — он закрывает форму и дополнительно вызывает обработчик ОбработкаВыбора у формы-владельца.

Частая задача — не дать закрыть форму с несохранёнными изменениями. Решается через ПередЗакрытием:

&НаКлиенте
Процедура ПередЗакрытием(Отказ, ЗавершениеРаботы, ТекстПредупреждения,
    СтандартнаяОбработка)
    Если Не Модифицированность Тогда
        Возврат;
    КонецЕсли;
    Отказ = Истина;
    СтандартнаяОбработка = Ложь;
    Оповещение = Новый ОписаниеОповещения("ПередЗакрытиемЗавершение", ЭтотОбъект);
    ПоказатьВопрос(Оповещение, "Данные изменены. Закрыть без сохранения?",
        РежимДиалогаВопрос.ДаНет);
КонецПроцедуры

&НаКлиенте
Процедура ПередЗакрытиемЗавершение(Ответ, ДополнительныеПараметры) Экспорт
    Если Ответ = КодВозвратаДиалога.Да Тогда
        Модифицированность = Ложь;
        Закрыть();
    КонецЕсли;
КонецПроцедуры

Схема такая: сначала отменяем закрытие (Отказ = Истина), затем асинхронно спрашиваем пользователя и в обработчике ответа либо закрываем форму, сбросив Модифицированность, либо оставляем как есть. Напрямую задать вопрос в ПередЗакрытием и дождаться ответа нельзя — диалоги в 8.3 работают только через оповещения.

Ошибки, на которых спотыкаются чаще всего

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

Вызов ОткрытьФорму на сервере. Метод клиентский. Если поставить его в процедуру с директивой &НаСервере, конфигурация не соберётся. Открытие формы инициируют только из клиентского кода: обработчик кнопки, события поля, команды.

Опечатка в имени формы. Строка "Справочник.Наменклатура.ФормаОбъекта" не вызовет подсветку в конфигураторе, но в рантайме упадёт с ошибкой «форма не найдена». Проверяйте регистр и копируйте имя из синтакс-помощника, а не печатайте вручную.

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

Обращение к реквизиту через Элементы вместо Объект. Элементы.Цена.Значение не существует — у элемента нет такого свойства. Значение лежит в Объект.Цена, а Элементы.Цена управляет лишь внешним видом поля.

Хранение полученной формы в переменной модуля. После закрытия окна ссылка на форму становится недействительной. Обращение к ней позже выдаст ошибку. ПолучитьФорму вызывают непосредственно перед открытием и больше к результату не возвращаются.

Чем отличается `ОткрытьФорму` от `ПолучитьФорму`?
ОткрытьФорму создаёт форму и сразу показывает окно, ничего не возвращая для дальнейшей работы. ПолучитьФорму возвращает объект формы, но не открывает его — можно настроить реквизиты и вызвать Открыть() вручную.
Почему мой параметр доступен в `ПриСозданииНаСервере`, а дальше теряется?
Произвольные параметры формы по умолчанию живут только во время создания. Чтобы параметр сохранялся всю жизнь формы, объявите его в свойствах формы и включите признак «Всегда использовать».
Как открыть форму в режиме только для чтения?
Либо через ПолучитьФорму установить свойство ТолькоПросмотр = Истина до открытия, либо передать собственный параметр и в ПриСозданииНаСервере выставить ТолькоПросмотр для формы или отдельных элементов.
Как получить значение, которое пользователь выбрал в открытой форме?
Передайте в ОткрытьФорму параметр ОписаниеОповещенияОЗакрытии с клиентской процедурой-обработчиком. Форма выбора при закрытии через Закрыть(Значение) или ОповеститьОВыборе(Значение) вернёт результат в этот обработчик.
В чём разница между `Элементы.Поле` и `Объект.Поле`?
Элементы.Поле — это элемент управления на форме (его видимость, доступность, оформление). Объект.Поле — реквизит данных объекта (само значение). Менять видимость нужно у элемента, а записывать значение — в реквизит объекта.