Представляю Вашему вниманию расширенные фильтры (отборы) на форме отчета, построенного на СКД.
Предыстория
Ни для кого не секрет, что СКД позволяет размещать свои отборы на форме, установив одну лишь галочку в настройках
После чего на форме отчета получить следующее
Свою функцию отбор выполнит, но с видом сравнения "Равно". СКД позволяет настроить поле отбора:
В этом окне можно указать любой доступный вид сравнения.
Но все это выглядит не очень красиво, особенно если этих отборов больше 6. А пользователю нравится когда удобно, все под рукой и фильтры не занимают пол экрана.
Предлагаю Вашему внимаю программное формирования группы отборов на форме, со всеми возможностями СКД.
Выглядеть это будет так:
При желании количество групп с фильтрами можно увеличить. Также программная обработка отборов позволяет использовать свои собственные условия, подмены значений, обработки выбора, скрытые фильтры и тд. Подобный подход также можно использовать для динамического списка.
В пруфах исходный код
#Область СлужебныеПроцедуры
Процедура ИнициализироватьОтборыНаФорме(Форма) Экспорт
СписокРеквизитов = Новый Структура();
// создадим реквизиты отборов на форме
СоздатьРеквизитыОтборовНаФорме(Форма,СписокРеквизитов);
// расположим элементы на форме
РасположитьЭлементыНаФорме(Форма,СписокРеквизитов);
КонецПроцедуры
Процедура СоздатьРеквизитыОтборовНаФорме(Форма,СписокРеквизитов)
ДобавляемыеРеквизиты = Новый Массив;
Для Каждого ДоступноеПолеОтбора Из ЭтотОбъект.КомпоновщикНастроек.Настройки.ДоступныеПоляОтбора.Элементы Цикл
ИмяРеквизита = Строка(ДоступноеПолеОтбора.Поле);
// добавим элемент отбора
ДобавитьЭлементОтбора(ИмяРеквизита);
// добавим реквизит "Использовать"
ДобавитьРеквизитНаФорму(ДобавляемыеРеквизиты,"Использовать_"+ИмяРеквизита,Тип("Булево"));
// добавим реквизит "ВидСравнения"
ДобавитьРеквизитНаФорму(ДобавляемыеРеквизиты,"ВидСравнения_"+ИмяРеквизита,Тип("Неопределено"));
// добавим реквизит "Использовать"
ДобавитьРеквизитНаФорму(ДобавляемыеРеквизиты,"ПравоеЗначение_"+ИмяРеквизита,ДоступноеПолеОтбора.Тип);
// добавим реквизит "Использовать"
ДобавитьРеквизитНаФорму(ДобавляемыеРеквизиты,"ПравоеЗначениеСписок_"+ИмяРеквизита,Тип("СписокЗначений"));
// сохраним данные создаваемго реквизита
СписокРеквизитов.Вставить(ИмяРеквизита,ИмяРеквизита);
КонецЦикла;
Форма.ИзменитьРеквизиты(ДобавляемыеРеквизиты);
КонецПроцедуры
Процедура ДобавитьЭлементОтбора(ИмяРеквизита)
ЭлементОтбора = ЭтотОбъект.КомпоновщикНастроек.Настройки.Отбор.Элементы.Добавить(тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных(ИмяРеквизита);
ЭлементОтбора.Использование = Ложь;
ЭлементОтбора.РежимОтображения = РежимОтображенияЭлементаНастройкиКомпоновкиДанных.БыстрыйДоступ;
ЭлементОтбора.ИдентификаторПользовательскойНастройки = новый УникальныйИдентификатор;
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
КонецПроцедуры
Процедура ДобавитьРеквизитНаФорму(ДобавляемыеРеквизиты,ИмяРеквизита,Тип)
МассивТипов = новый Массив;
МассивТипов.Добавить(Тип);
ОписаниеТипов = Новый ОписаниеТипов(МассивТипов);
Если ТипЗнч(Тип) = ТИП("ОписаниеТипов") Тогда
ОписаниеТипов = Тип;
КонецЕсли;
Реквизит = Новый РеквизитФормы("Отбор_" + ИмяРеквизита, ОписаниеТипов,,, Ложь);
ДобавляемыеРеквизиты.Добавить(Реквизит);
КонецПроцедуры
Процедура РасположитьЭлементыНаФорме(Форма,СписокРеквизитов)
ГруппаФильтра = Форма.Элементы.Добавить("ГруппаФильтр", Тип("ГруппаФормы"));
ГруппаФильтра.Вид = ВидГруппыФормы.ОбычнаяГруппа;
ГруппаФильтра.Группировка = ГруппировкаПодчиненныхЭлементовФормы.Горизонтальная;
ГруппаФильтра.ОтображатьЗаголовок = Ложь;
ГруппаФильтра.Видимость = Ложь;
ГруппаФильтраЛевая = Форма.Элементы.Добавить("ГруппаФильтрыЛево", Тип("ГруппаФормы"),ГруппаФильтра);
ГруппаФильтраЛевая.Вид = ВидГруппыФормы.ОбычнаяГруппа;
ГруппаФильтраЛевая.Группировка = ГруппировкаПодчиненныхЭлементовФормы.Вертикальная;
ГруппаФильтраЛевая.ОтображатьЗаголовок = Ложь;
ГруппаФильтраПравая = Форма.Элементы.Добавить("ГруппаФильтрыПраво", Тип("ГруппаФормы"),ГруппаФильтра);
ГруппаФильтраПравая.Вид = ВидГруппыФормы.ОбычнаяГруппа;
ГруппаФильтраПравая.Группировка = ГруппировкаПодчиненныхЭлементовФормы.Вертикальная;
ГруппаФильтраПравая.ОтображатьЗаголовок = Ложь;
Форма.Элементы.Переместить(ГруппаФильтра,Форма,Форма.Элементы.Результат);
ЛеваяГруппа = Истина;
Для Каждого Реквизит Из СписокРеквизитов Цикл
ПолеОтбора = ЭтотОбъект.КомпоновщикНастроек.Настройки.ДоступныеПоляОтбора.Элементы.Найти(Реквизит.Значение);
Если ПолеОтбора = Неопределено Тогда
Продолжить;
КонецЕсли;
// Предустановим тип списка значений
Форма["Отбор_ПравоеЗначениеСписок_" + Реквизит.Значение].ТипЗначения = ПолеОтбора.Тип;
Если ЛеваяГруппа Тогда
ЭлементФормыГруппаФильтра = Форма.Элементы.Добавить("Отбор_ГруппаФильтра_" + Реквизит.Значение, Тип("ГруппаФормы"), Форма.Элементы.ГруппаФильтрыЛево);
Иначе
ЭлементФормыГруппаФильтра = Форма.Элементы.Добавить("Отбор_ГруппаФильтра_" + Реквизит.Значение, Тип("ГруппаФормы"), Форма.Элементы.ГруппаФильтрыПраво);
КонецЕсли;
ЛеваяГруппа = НЕ ЛеваяГруппа;
// ГРУППА РАСПОЛОЖЕНИЯ ОТБОРА
ЭлементФормыГруппаФильтра.Вид = ВидГруппыФормы.ОбычнаяГруппа;
ЭлементФормыГруппаФильтра.ОтображатьЗаголовок = Ложь;
ЭлементФормыГруппаФильтра.Группировка = ГруппировкаПодчиненныхЭлементовФормы.Горизонтальная;
ЭлементФормыГруппаФильтра.Отображение = ОтображениеОбычнойГруппы.Нет;
ЭлементФормыГруппаФильтра.РастягиватьПоГоризонтали = Истина;
ЭлементФормыГруппаФильтра.Объединенная = Ложь;
// ЭЛЕМЕНТ "Использовать"
ЭлементФормы = Форма.Элементы.Добавить("Отбор_Использовать_" + Реквизит.Значение, Тип("ПолеФормы"), ЭлементФормыГруппаФильтра);
ЭлементФормы.ПутьКДанным = "Отбор_Использовать_" + Реквизит.Значение;
ЭлементФормы.Вид = ВидПоляФормы.ПолеФлажка;
ЭлементФормы.ПоложениеЗаголовка = ПоложениеЗаголовкаЭлементаФормы.Право;
ЭлементФормы.ТолькоПросмотр = Ложь;
ЭлементФормы.ВертикальноеПоложениеВГруппе = ВертикальноеПоложениеЭлемента.Центр;
ЭлементФормы.Заголовок = " ";
ЭлементФормы.УстановитьДействие("ПриИзменении","ОтборПриИзменении");
// НАДПИСЬ С НАИМЕНОВАНИЕМ ОТБОРА
НадписьРеквизита = Форма.Элементы.Добавить("Отбор_Наименование_" + Реквизит.Значение, Тип("ДекорацияФормы"), ЭлементФормыГруппаФильтра);
НадписьРеквизита.Заголовок = ПолеОтбора.Заголовок;
НадписьРеквизита.ВертикальноеПоложениеВГруппе = ВертикальноеПоложениеЭлемента.Центр;
НадписьРеквизита.РастягиватьПоГоризонтали = Ложь;
// ЭЛЕМЕНТ "Вид сравнения"
ЭлементФормы = Форма.Элементы.Добавить("Отбор_ВидСравнения_" + Реквизит.Значение, Тип("ПолеФормы"), ЭлементФормыГруппаФильтра);
ЭлементФормы.ПутьКДанным = "Отбор_ВидСравнения_" + Реквизит.Значение;
ЭлементФормы.Вид = ВидПоляФормы.ПолеВвода;
ЭлементФормы.ПоложениеЗаголовка = ПоложениеЗаголовкаЭлементаФормы.Нет;
ЭлементФормы.ТолькоПросмотр = Ложь;
ЭлементФормы.РежимВыбораИзСписка = Истина;
ЭлементФормы.РедактированиеТекста = Ложь;
ЭлементФормы.Ширина = 10;
ЭлементФормы.Высота = 1;
ЭлементФормы.РастягиватьПоГоризонтали = Ложь;
ЭлементФормы.КнопкаВыбора = Ложь;
ЭлементФормы.УстановитьДействие("ПриИзменении","ОтборПриИзменении");
// заполним доступные виды сравнения
Если ПолеОтбора.ТипЗначения.СодержитТип(ТИП("Число")) Тогда
ЭлементФормы.СписокВыбора.Добавить(ВидСравненияКомпоновкиДанных.Больше);
ЭлементФормы.СписокВыбора.Добавить(ВидСравненияКомпоновкиДанных.Меньше);
ЭлементФормы.СписокВыбора.Добавить(ВидСравненияКомпоновкиДанных.Равно);
Иначе
Для Каждого СтрВидаСравнения Из ПолеОтбора.ДоступныеВидыСравнения Цикл
ЭлементФормы.СписокВыбора.Добавить(СтрВидаСравнения.Значение);
КонецЦикла;
КонецЕсли;
// по умолчанию значение "Равно"
Форма["Отбор_ВидСравнения_" + Реквизит.Значение] = ВидСравненияКомпоновкиДанных.Равно;
// Группа "Правое значение"
ЭлементФормыПраваяГруппа = Форма.Элементы.Добавить("Отбор_ГруппаПравоеЗначение_" + Реквизит.Значение, Тип("ГруппаФормы"), ЭлементФормыГруппаФильтра);
ЭлементФормыПраваяГруппа.Вид = ВидГруппыФормы.ОбычнаяГруппа;
ЭлементФормыПраваяГруппа.ОтображатьЗаголовок = Ложь;
ЭлементФормыПраваяГруппа.Группировка = ГруппировкаПодчиненныхЭлементовФормы.Горизонтальная;
ЭлементФормыПраваяГруппа.Отображение = ОтображениеОбычнойГруппы.Нет;
ЭлементФормыПраваяГруппа.РастягиватьПоГоризонтали = Истина;
// ЭЛЕМЕНТ "Правое значение"
ЭлементФормы = Форма.Элементы.Добавить("Отбор_ПравоеЗначение_" + Реквизит.Значение, Тип("ПолеФормы"), ЭлементФормыПраваяГруппа);
ЭлементФормы.ПутьКДанным = "Отбор_ПравоеЗначение_" + Реквизит.Значение;
ЭлементФормы.Вид = ВидПоляФормы.ПолеВвода;
ЭлементФормы.ПоложениеЗаголовка = ПоложениеЗаголовкаЭлементаФормы.Нет;
ЭлементФормы.ТолькоПросмотр = Ложь;
ЭлементФормы.РежимРедактирования = РежимРедактированияКолонки.Непосредственно;
ЭлементФормы.КнопкаОткрытия = Ложь;
ЭлементФормы.АвтоМаксимальнаяШирина = Ложь;
ЭлементФормы.РастягиватьПоГоризонтали = Истина;
ЭлементФормы.Ширина = 15;
ЭлементФормы.АвтоВыборНезаполненного = Ложь;
ЭлементФормы.ОбновлениеТекстаРедактирования = ОбновлениеТекстаРедактирования.ПриИзмененииЗначения;
ЭлементФормы.УстановитьДействие("ПриИзменении","ОтборПриИзменении");
ЭлементФормы.УстановитьДействие("НачалоВыбора","ОтборНачалоВыбора");
// ЭЛЕМЕНТ "Правое значение список"
ЭлементФормы = Форма.Элементы.Добавить("Отбор_ПравоеЗначениеСписок_" + Реквизит.Значение, Тип("ПолеФормы"), ЭлементФормыПраваяГруппа);
ЭлементФормы.ПутьКДанным = "Отбор_ПравоеЗначениеСписок_" + Реквизит.Значение;
ЭлементФормы.Вид = ВидПоляФормы.ПолеВвода;
ЭлементФормы.ПоложениеЗаголовка = ПоложениеЗаголовкаЭлементаФормы.Нет;
ЭлементФормы.ТолькоПросмотр = Ложь;
ЭлементФормы.РежимРедактирования = РежимРедактированияКолонки.Непосредственно;
ЭлементФормы.КнопкаОткрытия = Ложь;
ЭлементФормы.Видимость = Ложь;
ЭлементФормы.АвтоМаксимальнаяШирина = Ложь;
ЭлементФормы.РастягиватьПоГоризонтали = Истина;
ЭлементФормы.Ширина = 15;
ЭлементФормы.УстановитьДействие("ПриИзменении","ОтборПриИзменении");
КонецЦикла;
КонецПроцедуры
#КонецОбласти
#Область ОбработчикиФормы
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
ОтчетОбъект = РеквизитФормыВЗначение("Отчет");
ОтчетОбъект.ИнициализироватьОтборыНаФорме(ЭтаФорма);
КонецПроцедуры
#КонецОбласти
#Область ПодключаемыеОбработчикиОтборов
&НаКлиенте
Процедура ПоказатьНастройки(Команда)
Если Элементы.ГруппаФильтр.Видимость Тогда
Элементы.ФормаПоказатьНастройки.Заголовок = "Показать фильтры";
Иначе
Элементы.ФормаПоказатьНастройки.Заголовок = "Скрыть фильтры";
КонецЕсли;
Элементы.ГруппаФильтр.Видимость = Не Элементы.ГруппаФильтр.Видимость;
КонецПроцедуры
&НаКлиенте
Процедура ОтборПриИзменении(Элемент)
ОтборПриИзмененииНаСервере(Строка(Элемент.Имя));
КонецПроцедуры
&НаСервере
Процедура ОтборПриИзмененииНаСервере(Имя)
Если НЕ Найти(Имя,"Отбор") = 0 Тогда
Имя = Сред(Имя,7);
ПоложениеПробела = СтрНайти(Имя,"_");
Если ПоложениеПробела = 0 Тогда
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Ошибка применения фильтра";
Сообщение.Сообщить();
Возврат;
КонецЕсли;
ИмяПоля = Сред(Имя,1,ПоложениеПробела-1);
ИмяРеквизита = Сред(Имя,ПоложениеПробела+1);
Если ИмяПоля = "ВидСравнения" Тогда
ТекущееЗначение = ЭтаФорма["Отбор_ВидСравнения_" + ИмяРеквизита];
Если Найти(ВРег(ТекущееЗначение), "СПИС") = 0 Тогда
Элементы["Отбор_ПравоеЗначение_" + ИмяРеквизита].Видимость = Истина;
Элементы["Отбор_ПравоеЗначениеСписок_" + ИмяРеквизита].Видимость = Ложь;
Если Не ЭтаФорма["Отбор_ПравоеЗначениеСписок_" + ИмяРеквизита].Количество() = 0 Тогда
ЭтаФорма["Отбор_ПравоеЗначение_" + ИмяРеквизита] = ЭтаФорма["Отбор_ПравоеЗначениеСписок_" + ИмяРеквизита][0].Значение;
ЭтаФорма["Отбор_ПравоеЗначениеСписок_" + ИмяРеквизита].Очистить();
КонецЕсли;
Иначе
Элементы["Отбор_ПравоеЗначение_" + ИмяРеквизита].Видимость = Ложь;
Элементы["Отбор_ПравоеЗначениеСписок_" + ИмяРеквизита].Видимость = Истина;
Если ЭтаФорма["Отбор_ПравоеЗначениеСписок_" + ИмяРеквизита].Количество() = 0 И ЗначениеЗаполнено(ЭтаФорма["Отбор_ПравоеЗначение_" + ИмяРеквизита]) Тогда
ЭтаФорма["Отбор_ПравоеЗначениеСписок_" + ИмяРеквизита].Добавить(ЭтаФорма["Отбор_ПравоеЗначение_" + ИмяРеквизита]);
ЭтаФорма["Отбор_ПравоеЗначение_" + ИмяРеквизита] = Неопределено;
КонецЕсли;
КонецЕсли;
КонецЕсли;
ТекущийОтбор = Неопределено;
//Найдем отбор
Для Каждого СтрОтбор Из Отчет.КомпоновщикНастроек.Настройки.Отбор.Элементы Цикл
Если Строка(СтрОтбор.ЛевоеЗначение) = ИмяРеквизита Тогда
ТекущийОтбор = СтрОтбор;
КонецЕсли;
КонецЦикла;
Если Не ТекущийОтбор = Неопределено Тогда
Если Не (ЭтаФорма["Отбор_Использовать_" + ИмяРеквизита] = Ложь И ТекущийОтбор.Использование = Ложь) Тогда
Если Не ЭтаФорма["Отбор_ВидСравнения_" + ИмяРеквизита] = Неопределено Тогда
Попытка
ТекущийОтбор.ВидСравнения = ЭтаФорма["Отбор_ВидСравнения_" + ИмяРеквизита];
ТекЗначениеВидаСравнения = ЭтаФорма["Отбор_ВидСравнения_" + ИмяРеквизита];
Если Найти(ВРег(ТекЗначениеВидаСравнения), "СПИС") = 0 Тогда
ТекущийОтбор.ПравоеЗначение = ЭтаФорма["Отбор_ПравоеЗначение_" + ИмяРеквизита];
Иначе
ТекущийОтбор.ПравоеЗначение = ЭтаФорма["Отбор_ПравоеЗначениеСписок_" + ИмяРеквизита];
КонецЕсли;
ТекущийОтбор.Использование = ЭтаФорма["Отбор_Использовать_" + ИмяРеквизита];
Исключение
ЭтаФорма["Отбор_Использовать_" + ИмяРеквизита] = Ложь;
КонецПопытки;
Иначе
ЭтаФорма["Отбор_Использовать_" + ИмяРеквизита] = Ложь;
КонецЕсли;
Иначе
ТекЗначениеВидаСравнения = ЭтаФорма["Отбор_ВидСравнения_" + ИмяРеквизита];
Если Найти(ВРег(ТекЗначениеВидаСравнения), "СПИС") = 0 Тогда
Если ЗначениеЗаполнено(ЭтаФорма["Отбор_ПравоеЗначение_" + ИмяРеквизита]) И ЗначениеЗаполнено(ЭтаФорма["Отбор_ВидСравнения_" + ИмяРеквизита]) Тогда
Если ЭтаФорма["Отбор_Использовать_" + ИмяРеквизита] = Ложь Тогда
ЭтаФорма["Отбор_Использовать_" + ИмяРеквизита] = Истина;
ТекущийОтбор.ВидСравнения = ТекЗначениеВидаСравнения;
ТекущийОтбор.ПравоеЗначение = ЭтаФорма["Отбор_ПравоеЗначение_" + ИмяРеквизита];
ТекущийОтбор.Использование = Истина;
КонецЕсли;
КонецЕсли;
Иначе
Если ЗначениеЗаполнено(ЭтаФорма["Отбор_ПравоеЗначениеСписок_" + ИмяРеквизита])
И ЗначениеЗаполнено(ЭтаФорма["Отбор_ВидСравнения_" + ИмяРеквизита]) Тогда
Если ЭтаФорма["Отбор_Использовать_" + ИмяРеквизита] = Ложь Тогда
ЭтаФорма["Отбор_Использовать_" + ИмяРеквизита] = Истина;
ТекущийОтбор.ВидСравнения = ТекЗначениеВидаСравнения;
ТекущийОтбор.ПравоеЗначение = ЭтаФорма["Отбор_ПравоеЗначениеСписок_" + ИмяРеквизита];
ТекущийОтбор.Использование = Истина;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
#КонецОбласти
Пример использования программных отборов отчета на СКД тестировался на платформе 8.3.13.1644.
Режим совместимости 8.3.10