Как открыть вспомогательную форму выбора при создании документа на основании в 1С на обычных формах

Программист 1С v8.3 (Обычные формы) Промышленность, строительство и АПК
← На главную

При разработке в конфигурациях на обычных формах (например, УПП 1.3 или КА 1.1) часто возникает задача: при создании одного документа на основании другого необходимо запросить у пользователя дополнительные данные. Это может быть выбор типа стоимости, склада, ответственного или специфического режима заполнения табличной части. Основная сложность заключается в том, что стандартный механизм 1С разделяет логику заполнения данных и логику отображения интерфейса. Рассмотрим подробно, почему возникают трудности и как их правильно обойти.

Почему нельзя открыть форму в процедуре ОбработкаЗаполнения

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

Попытка вызвать ОткрытьФорму() или любой другой интерактивный метод в модуле объекта приведет к ошибке выполнения. Поэтому нам необходимо перенести логику взаимодействия с пользователем в модуль формы создаваемого документа или в форму исходного документа.

Способ 1. Использование обработчика ожидания в процедуре ПриОткрытии

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

Проанализируем алгоритм действий:

  1. В основной форме нового документа (Документ2) находим процедуру ПриОткрытии.
  2. Проверяем, является ли создание документа вводом на основании (проверяем заполнение параметра Основание или наличие данных в табличных частях).
  3. Подключаем обработчик ожидания на очень короткий срок (0.1 сек), который сработает сразу после того, как форма документа полностью отрисуется на экране.

Рассмотрим пример кода в модуле формы Документа2:


Процедура ПриОткрытии()
    // Проверяем, что это новый документ и он создается на основании
    Если ЭтоНовый() И ЗначениеЗаполнено(ПараметрОснование) Тогда
        // Подключаем одноразовый обработчик ожидания
        ПодключитьОбработчикОжидания("ВыполнитьИнтерактивныйВыбор", 0.1, Истина);
    КонецЕсли;
КонецПроцедуры

Процедура ВыполнитьИнтерактивныйВыбор() Экспорт
    // Настраиваем параметры открытия формы выбора
    ПараметрыВыбора = Новый Структура("ВыборНаОсновании", Истина);
    
    // Открываем форму модально или с описанием оповещения
    Результат = ОткрытьФормуМодально("Документ.ОприходованиеМатериаловИзПроизводства.Форма.МС_ФормаВыбораТипаСтоимости", ПараметрыВыбора, ЭтаФорма);
    
    // Если пользователь что-то выбрал, заполняем данные
    Если Результат <> Неопределено Тогда
        Для Каждого СтрокаТЧ Из ЭтотОбъект.Товары Цикл
            СтрокаТЧ.ТипСтоимости = Результат;
        КонецЦикла;
    КонецЕсли;
КонецПроцедуры

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

Способ 2. Использование режима блокировки окна владельца

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

Рассмотрим, как изменить процедуру вызова:


Процедура ОткрытьФормаВыбораТипаСтоимости() Экспорт
    // Указываем владельцем текущую форму
    ФормаВыбора = ПолучитьФорму("Документ.ОприходованиеМатериаловИзПроизводства.Форма.МС_ФормаВыбораТипаСтоимости", , ЭтаФорма);
    ФормаВыбора.РежимОткрытияОкнаФормы = РежимОткрытияОкнаФормы.БлокироватьОкноВладельца;
    ФормаВыбора.Открыть();
КонецПроцедуры

В этом случае в самой форме выбора при нажатии кнопки "ОК" нужно будет обратиться к владельцу формы и вызвать у него экспортную процедуру для обновления данных. Например: ЭтаФорма.ВладелецФормы.ОбновитьДанныеДокумента(ВыбранноеЗначение);.

Способ 3. Перехват управления в исходном документе (Чистый подход)

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

Пошаговый план реализации:

  1. В форме Документа1 создаем кнопку или перехватываем действие в меню "Ввести на основании".
  2. Сначала открываем форму выбора параметров.
  3. После успешного выбора создаем объект нового документа программно.
  4. Передаем выбранные параметры в процедуру Заполнить() или через ДополнительныеСвойства.
  5. Открываем форму уже заполненного документа.

Пример реализации в форме исходного документа:


Процедура КомандаВвестиНаОснованииСВыбором(Кнопка)
    // 1. Сначала спрашиваем пользователя
    ТипСтоимости = ОткрытьФормуМодально("Документ.ОприходованиеМатериаловИзПроизводства.Форма.МС_ФормаВыбораТипаСтоимости");
    
    Если ТипСтоимости = Неопределено Тогда
        Возврат; // Пользователь передумал
    КонецЕсли;

    // 2. Создаем новый документ программно
    НовыйДокумент = Документы.ОприходованиеМатериаловИзПроизводства.СоздатьДокумент();
    
    // Передаем основание и параметры
    НовыйДокумент.Заполнить(ЭтотОбъект.Ссылка);
    
    // Дозаполняем выбранным значением
    Для Каждого Стр Из НовыйДокумент.Товары Цикл
        Стр.ТипСтоимости = ТипСтоимости;
    КонецЦикла;
    
    // 3. Открываем форму уже готового документа
    ФормаНового = НовыйДокумент.ПолучитьФорму();
    ФормаНового.Открыть();
КонецПроцедуры

Рекомендации по обработке закрытия

Выясним причину, по которой пользователи часто жалуются на этот механизм. Часто бывает, что пользователь открыл форму выбора, понял, что создание на основании ему не нужно, и нажал "Отмена". Если вы используете Способ 1 (через форму нового документа), то у пользователя останется открытая форма пустого или недозаполненного документа.

Чтобы избежать этой ситуации, в коде обработки результата выбора добавьте проверку: если выбор не сделан (результат равен Неопределено), следует программно закрыть основную форму документа командой ЭтаФорма.Закрыть(Ложь);. Таким образом, процесс будет выглядеть бесшовным: нажали "Ввести на основании" -> появилось окно выбора -> нажали "Отмена" -> ничего не произошло.

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

← На главную