При разработке отчетов на базе объекта ПостроительОтчета (традиционно используемого в обычных формах) программисты часто сталкиваются с ограничением: если поле отбора является вычисляемым или строковым, платформа предлагает пользователю вводить значение вручную. Это неудобно и чревато ошибками ввода. В отличие от системы компоновки данных (СКД), где существует метод УстановитьДоступныеЗначения, в ПостроителеОтчета такой функционал «из коробки» для произвольных типов отсутствует.
В данной статье мы подробно разберем, как программно перехватить управление процессом выбора и подставить пользователю заранее определенный список значений, чтобы сделать интерфейс более профессиональным и удобным.
Рассмотрим ситуацию: у нас есть запрос, объединяющий данные из разных документов. Мы добавляем виртуальное поле ДокВид, которое содержит строковое представление типа документа (например, «Заказ» или «Уст.Цен»). В тексте запроса это выглядит так:
"ВЫБРАТЬ
| ""Заказ"" КАК ДокВид,
| Заказ.Ссылка КАК Документ
|...
|{ГДЕ
| (""Заказ"") КАК ДокВид}"
Проблема заключается в том, что в окне настроек отчета в колонке «Значение» для этого поля будет доступно только текстовое поле ввода. Если пользователь ошибется хоть в одном символе, отчет не вернет данных. Наша задача — заставить систему предлагать выбор из списка.
Самый надежный способ — это работа с элементами управления формы. Если отбор ПостроителяОтчета выведен на форму в виде табличного поля, мы можем использовать его события. Проанализируем алгоритм перехвата в обработчике НачалоВыбора для колонки «Значение».
Нам необходимо убедиться, что пользователь нажал кнопку выбора именно в строке с нашим полем ДокВид. Рассмотрим пример кода:
Процедура ОтборНачалоВыбора(Элемент, ДанныеСобытия, СтандартнаяОбработка)
ТекущаяСтрока = Элемент.ТекущиеДанные;
// Проверяем, что это именно наше поле
Если ТекущаяСтрока.ПутьКДанным = "ДокВид" Тогда
СтандартнаяОбработка = Ложь; // Отключаем стандартный ввод строки
СписокВыбора = Новый СписокЗначений;
СписокВыбора.Добавить("Заказ", "Заказ поставщику");
СписокВыбора.Добавить("Уст.Цен", "Установка цен");
// Показываем список пользователю
ВыбранныйЭлемент = ВыбратьИзСписка(СписокВыбора, Элемент);
Если ВыбранныйЭлемент <> Неопределено Тогда
ТекущаяСтрока.Значение = ВыбранныйЭлемент.Значение;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Ситуация усложняется, когда пользователь выбирает вид сравнения ВидСравнения.ВСписке или ВидСравнения.НеВСписке. В этом случае типом значения в строке отбора становится не Строка, а СписокЗначений. Если мы просто подставим одну строку, это вызовет ошибку типа данных.
Рассмотрим, как правильно обработать множественный выбор. Проанализируем логику: если выбран вид сравнения для списка, мы должны открыть форму подбора с флагами или позволить пользователю выбрать несколько элементов из нашего предопределенного набора.
Если ТекущаяСтрока.ВидСравнения = ВидСравнения.ВСписке
ИЛИ ТекущаяСтрока.ВидСравнения = ВидСравнения.НеВСписке Тогда
СтандартнаяОбработка = Ложь;
// Создаем список всех возможных значений с пометками
СписокДляВыбора = Новый СписокЗначений;
СписокДляВыбора.Добавить("Заказ");
СписокДляВыбора.Добавить("Уст.Цен");
// Если в отборе уже что-то есть, проставим пометки
Если ТипЗнч(ТекущаяСтрока.Значение) = Тип("СписокЗначений") Тогда
Для Каждого ЭлементИзОтбора Из ТекущаяСтрока.Значение Цикл
Найденный = СписокДляВыбора.НайтиПоЗначению(ЭлементИзОтбора.Значение);
Если Найденный <> Неопределено Тогда
Найденный.Пометка = Истина;
КонецЕсли;
КонецЦикла;
КонецЕсли;
// Открываем список для множественного выбора (отметки)
Если СписокДляВыбора.ОтметитьЭлементы("Выберите виды документов") Тогда
// Очищаем и заполняем список в отборе заново
НовыйСписокЗначений = Новый СписокЗначений;
Для Каждого Стр Из СписокДляВыбора Цикл
Если Стр.Пометка Тогда
НовыйСписокЗначений.Добавить(Стр.Значение);
КонецЕсли;
КонецЦикла;
ТекущаяСтрока.Значение = НовыйСписокЗначений;
КонецЕсли;
КонецЕсли;
Чтобы сделать интерфейс еще более «отзывчивым», мы можем использовать событие АвтоПодборТекста. Это позволит пользователю начать вводить название (например, «За...») и получить автоматическое предложение «Заказ».
Для реализации этого подхода в обработчике события ПриАктивизацииЯчейки или в момент инициализации формы настроек можно принудительно установить колонке режим выбора из списка. Однако, учитывая специфику ПостроителяОтчета, где строки динамически меняются, лучше использовать комбинацию событий ОкончаниеРедактирования и НачалоВыбора.
Разберем важный нюанс: свойство СписокЗначений у объекта ПолеНастройки (в коллекции ПостроительОтчета.ДоступныеПоля) часто доступно только для чтения и имеет значение Неопределено для строковых полей. Попытка программно инициализировать его напрямую обычно не приводит к появлению кнопки выбора в стандартном окне настроек. Именно поэтому использование событий табличного поля является наиболее стабильным «костылем» для решения этой задачи.
Если проект позволяет, мы настоятельно рекомендуем рассмотреть возможность перевода отчета на Систему компоновки данных (СКД). В СКД эта задача решается значительно элегантнее через объект ПолеНабораДанныхСхемыКомпоновкиДанных.
Проанализируем пример для СКД:
УстановитьДоступныеЗначения().
// Пример для СКД
ДоступныеЗначения = Новый СписокЗначений;
ДоступныеЗначения.Добавить("Заказ");
ДоступныеЗначения.Добавить("Уст.Цен");
Поле = СхемаКомпоновкиДанных.НаборыДанных.НаборДанных1.Поля.Найти("ДокВид");
Поле.УстановитьДоступныеЗначения(ДоступныеЗначения);
После выполнения этого кода в любом интерфейсе (управляемом или обычном) платформа автоматически ограничит выбор пользователя указанным списком, корректно обрабатывая как одиночные значения, так и списки для сравнения.
Мы выяснили, что напрямую ограничить список выбора в ПостроителеОтчета через свойства метаданных или настройки самого объекта практически невозможно. Основные способы решения задачи в обычных формах — это:
Применяя эти технические приемы, вы сможете создать качественный и отказоустойчивый интерфейс для своих пользователей, минимизировав количество ошибок при формировании сложных отчетов.