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