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