Как ограничить выбор в поле отбора Построителя отчета фиксированным списком значений

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

При разработке отчетов на базе объекта ПостроительОтчета (традиционно используемого в обычных формах) программисты часто сталкиваются с ограничением: если поле отбора является вычисляемым или строковым, платформа предлагает пользователю вводить значение вручную. Это неудобно и чревато ошибками ввода. В отличие от системы компоновки данных (СКД), где существует метод УстановитьДоступныеЗначения, в ПостроителеОтчета такой функционал «из коробки» для произвольных типов отсутствует.

В данной статье мы подробно разберем, как программно перехватить управление процессом выбора и подставить пользователю заранее определенный список значений, чтобы сделать интерфейс более профессиональным и удобным.

Постановка задачи и анализ ситуации

Рассмотрим ситуацию: у нас есть запрос, объединяющий данные из разных документов. Мы добавляем виртуальное поле ДокВид, которое содержит строковое представление типа документа (например, «Заказ» или «Уст.Цен»). В тексте запроса это выглядит так:


"ВЫБРАТЬ
|    ""Заказ"" КАК ДокВид,
|    Заказ.Ссылка КАК Документ
|...
|{ГДЕ
|    (""Заказ"") КАК ДокВид}"

Проблема заключается в том, что в окне настроек отчета в колонке «Значение» для этого поля будет доступно только текстовое поле ввода. Если пользователь ошибется хоть в одном символе, отчет не вернет данных. Наша задача — заставить систему предлагать выбор из списка.

Способ 1. Использование события НачалоВыбора в табличном поле

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

Нам необходимо убедиться, что пользователь нажал кнопку выбора именно в строке с нашим полем ДокВид. Рассмотрим пример кода:


Процедура ОтборНачалоВыбора(Элемент, ДанныеСобытия, СтандартнаяОбработка)
    
    ТекущаяСтрока = Элемент.ТекущиеДанные;
    
    // Проверяем, что это именно наше поле
    Если ТекущаяСтрока.ПутьКДанным = "ДокВид" Тогда
        
        СтандартнаяОбработка = Ложь; // Отключаем стандартный ввод строки
        
        СписокВыбора = Новый СписокЗначений;
        СписокВыбора.Добавить("Заказ", "Заказ поставщику");
        СписокВыбора.Добавить("Уст.Цен", "Установка цен");
        
        // Показываем список пользователю
        ВыбранныйЭлемент = ВыбратьИзСписка(СписокВыбора, Элемент);
        
        Если ВыбранныйЭлемент <> Неопределено Тогда
            ТекущаяСтрока.Значение = ВыбранныйЭлемент.Значение;
        КонецЕсли;
        
    КонецЕсли;

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

Способ 2. Обработка сложных видов сравнения («В списке», «Не в списке»)

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

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


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

Способ 3. Автоподбор текста и режим выбора из списка

Чтобы сделать интерфейс еще более «отзывчивым», мы можем использовать событие АвтоПодборТекста. Это позволит пользователю начать вводить название (например, «За...») и получить автоматическое предложение «Заказ».

Для реализации этого подхода в обработчике события ПриАктивизацииЯчейки или в момент инициализации формы настроек можно принудительно установить колонке режим выбора из списка. Однако, учитывая специфику ПостроителяОтчета, где строки динамически меняются, лучше использовать комбинацию событий ОкончаниеРедактирования и НачалоВыбора.

Разберем важный нюанс: свойство СписокЗначений у объекта ПолеНастройки (в коллекции ПостроительОтчета.ДоступныеПоля) часто доступно только для чтения и имеет значение Неопределено для строковых полей. Попытка программно инициализировать его напрямую обычно не приводит к появлению кнопки выбора в стандартном окне настроек. Именно поэтому использование событий табличного поля является наиболее стабильным «костылем» для решения этой задачи.

Рекомендация: переход на СКД

Если проект позволяет, мы настоятельно рекомендуем рассмотреть возможность перевода отчета на Систему компоновки данных (СКД). В СКД эта задача решается значительно элегантнее через объект ПолеНабораДанныхСхемыКомпоновкиДанных.

Проанализируем пример для СКД:

  1. В схеме компоновки находим нужное поле набора данных.
  2. Используем метод УстановитьДоступныеЗначения().

// Пример для СКД
ДоступныеЗначения = Новый СписокЗначений;
ДоступныеЗначения.Добавить("Заказ");
ДоступныеЗначения.Добавить("Уст.Цен");

Поле = СхемаКомпоновкиДанных.НаборыДанных.НаборДанных1.Поля.Найти("ДокВид");
Поле.УстановитьДоступныеЗначения(ДоступныеЗначения);

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

Итоги

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

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

← На главную