Не раз случалось выносить на форму таблицу значений, в которой пользователь просматривал некие данные. Весьма часто приходилось делать такие отборы и настраиваемую сортировку. Спустя какое то время пришла мысль сделать что то универсальное, дабы не делать это каждый раз. Решил вот вынести свое творение на суд общественности.
Обработка импортируется в конфигурацию, через "Вставить внешнюю обработку, отчет". Можно добавить как общую форму, так как весь код размещен в форме. В форму передается сама таблица значений, строка с именами полей отборов, которые разрешено использовать пользователю, строка с именами полей для сортировки, заголовок формы отбора. Далее в нужных местах вставляем нижеследующий код, ну или что-то похожее.
ИменаПолейОтбора = "Колонка1;Колонка2;Колонка3;Колонка4;Колонка5;Колонка6;Колонка7;Колонка8;Колонка9;Колонка10;Колонка11;Колонка12";
НастройкиОтбора = Новый Структура;
НастройкиОтбора.Вставить("ИменаПолейОтбора", ИменаПолейОтбора);
НастройкиОтбора.Вставить("ИменаПолейСортировки", ИменаПолейОтбора);
НастройкиОтбора.Вставить("ТабДанные", ТабЗнач);
НастройкиОтбора.Вставить("ЗаголовокФормы", "Настройте отбор таблицы значений");
ФормаУО = Обработки.ФормаУниверсальногоОтбора.ПолучитьФорму("ФормаУниверсальногоОтбора");
ФормаУО.НастройкиОтбора = НастройкиОтбора;
ТабДанные = ФормаУО.ОткрытьМодально();
Если ТабДанные <> Неопределено Тогда
ТабЗнач.Очистить();
Для каждого ТекСтр Из ТабДанные Цикл
НовСтр = ТабЗнач.Добавить();
ЗаполнитьЗначенияСвойств(НовСтр, ТекСтр);
КонецЦикла;
КонецЕсли;
Набор элементов для каждого поля отбора создается программно.
ПанельДляЭлементов = ЭлементыФормы.Панель1;
ВертИнтервал = 3;
//флажок
НовыйФлажок = ЭлементыФормы.Добавить(Тип("Флажок"), "фл" + ИмяКолонки, Истина, ПанельДляЭлементов);
НовыйФлажок.Лево = 8;
НовыйФлажок.Ширина = 131;
НовыйФлажок.Высота = 19;
НовыйФлажок.Верх = 6 + (19 + ВертИнтервал) * НомерЭлемента;
НовыйФлажок.Заголовок = Заголовок;
//вид сравнения заполняем в зависимости от типа данных
СписокВидовСравнения = СформироватьСписокВидовСравнения(ТипЗначения);
НовыйВидСравнения = ЭлементыФормы.Добавить(Тип("ПолеВвода"), "ВидСравнения" + ИмяКолонки, Истина, ПанельДляЭлементов);
НовыйВидСравнения.ТипЗначения = Новый ОписаниеТипов("ВидСравнения");
НовыйВидСравнения.РежимВыбораИзСписка = Истина;
НовыйВидСравнения.СписокВыбора = СписокВидовСравнения;
НовыйВидСравнения.КнопкаВыбора = Ложь;
НовыйВидСравнения.Лево = 144;
НовыйВидСравнения.Ширина = 111;
НовыйВидСравнения.Высота = 19;
НовыйВидСравнения.Верх = 6 + (19 + ВертИнтервал) * НомерЭлемента;
НовыйВидСравнения.УстановитьДействие("ПриИзменении", Новый Действие("ПриИзмененииПоляВидаСравнения"));
//поле значения
//для типов дата и число, создаем изначально два поля, но одно из них делаем невидимым
Если ЕстьТипЧислоДата(ТипЗначения) Тогда
НовоеПолеЗначения = ЭлементыФормы.Добавить(Тип("ПолеВвода"), "ПолеЗначения" + ИмяКолонки, Истина, ПанельДляЭлементов);
НовоеПолеЗначения.ТипЗначения = ТипЗначения;
НовоеПолеЗначения.Лево = 260;
НовоеПолеЗначения.Ширина = 120;
НовоеПолеЗначения.Высота = 19;
НовоеПолеЗначения.Верх = 6 + (19 + ВертИнтервал) * НомерЭлемента;
Если ЭтоСоставнойТип(ТипЗначения) Тогда
НовоеПолеЗначения.ВыбиратьТип = Истина;
НовоеПолеЗначения.КнопкаВыбора = Истина;
НовоеПолеЗначения.КнопкаОчистки = Истина;
КонецЕсли;
НовоеПолеЗначения.УстановитьДействие("ПриИзменении", Новый Действие("ПриИзмененииПоляПолеЗначения"));
НовоеПолеЗначения = ЭлементыФормы.Добавить(Тип("ПолеВвода"), "ПолеЗначения2" + ИмяКолонки, Ложь, ПанельДляЭлементов);
НовоеПолеЗначения.ТипЗначения = ТипЗначения;
НовоеПолеЗначения.Лево = 385;
НовоеПолеЗначения.Ширина = 120;
НовоеПолеЗначения.Высота = 19;
НовоеПолеЗначения.Верх = 6 + (19 + ВертИнтервал) * НомерЭлемента;
Если ЭтоСоставнойТип(ТипЗначения) Тогда
НовоеПолеЗначения.ВыбиратьТип = Истина;
НовоеПолеЗначения.КнопкаВыбора = Истина;
НовоеПолеЗначения.КнопкаОчистки = Истина;
КонецЕсли;
НовоеПолеЗначения.УстановитьДействие("ПриИзменении", Новый Действие("ПриИзмененииПоляПолеЗначения"));
Иначе
НовоеПолеЗначения = ЭлементыФормы.Добавить(Тип("ПолеВвода"), "ПолеЗначения" + ИмяКолонки, Истина, ПанельДляЭлементов);
НовоеПолеЗначения.ТипЗначения = ТипЗначения;
НовоеПолеЗначения.Лево = 260;
НовоеПолеЗначения.Ширина = 245;
НовоеПолеЗначения.Высота = 19;
НовоеПолеЗначения.Верх = 6 + (19 + ВертИнтервал) * НомерЭлемента;
Если ЭтоСоставнойТип(ТипЗначения) Тогда
НовоеПолеЗначения.ВыбиратьТип = Истина;
НовоеПолеЗначения.КнопкаВыбора = Истина;
НовоеПолеЗначения.КнопкаОчистки = Истина;
КонецЕсли;
НовоеПолеЗначения.УстановитьДействие("ПриИзменении", Новый Действие("ПриИзмененииПоляПолеЗначения"));
КонецЕсли;
Список видов сравнения настраивается для каждого типа данных индивидуально. Допускается использование составного типа данных в колонке таблицы значений.
Процедура ДобавитьВидыСравненияПоТипу(СписокВидовСравнения, ТипЗначения)
Если ТипЗначения = Тип("Строка") Тогда
СписокВидовСравнения.Добавить(ВидСравнения.Содержит);
СписокВидовСравнения.Добавить(ВидСравнения.НеСодержит);
ИначеЕсли ТипЗначения = Тип("Дата")
ИЛИ ТипЗначения = Тип("Число") Тогда
СписокВидовСравнения.Добавить(ВидСравнения.Больше);
СписокВидовСравнения.Добавить(ВидСравнения.БольшеИлиРавно);
СписокВидовСравнения.Добавить(ВидСравнения.Меньше);
СписокВидовСравнения.Добавить(ВидСравнения.МеньшеИлиРавно);
СписокВидовСравнения.Добавить(ВидСравнения.Интервал);
СписокВидовСравнения.Добавить(ВидСравнения.ИнтервалВключаяГраницы);
СписокВидовСравнения.Добавить(ВидСравнения.ИнтервалВключаяНачало);
СписокВидовСравнения.Добавить(ВидСравнения.ИнтервалВключаяОкончание);
Иначе
МетаданныеТипа = Метаданные.НайтиПоТипу(ТипЗначения);
//если тип - иерархический справочник
Если МетаданныеТипа <> Неопределено Тогда
МассивФрагментов = ЛксПолучитьМассивИзСтрокиСРазделителем(МетаданныеТипа.ПолноеИмя());
Если МассивФрагментов.Количество() И МассивФрагментов[0] = "Справочник"
И МетаданныеТипа.Иерархический Тогда
СписокВидовСравнения.Добавить(ВидСравнения.ВИерархии);
СписокВидовСравнения.Добавить(ВидСравнения.НеВИерархии);
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Функция СформироватьСписокВидовСравнения(ТипЗначения)
СписокВидовСравнения = Новый СписокЗначений;
СписокВидовСравнения.Добавить(ВидСравнения.Равно);
СписокВидовСравнения.Добавить(ВидСравнения.НеРавно);
СписокВидовСравнения.Добавить(ВидСравнения.ВСписке);
СписокВидовСравнения.Добавить(ВидСравнения.НеВСписке);
Если ТипЗнч(ТипЗначения) = Тип("ОписаниеТипов") Тогда
Для каждого ТекТип Из ТипЗначения.Типы() Цикл
ДобавитьВидыСравненияПоТипу(СписокВидовСравнения, ТекТип);
КонецЦикла;
Иначе
ДобавитьВидыСравненияПоТипу(СписокВидовСравнения, ТипЗначения);
КонецЕсли;
Возврат СписокВидовСравнения;
КонецФункции
На основании выбранных полей отбора и сортировки строится запрос к таблице значений, в котором отбираются необходимые данные. Возвращаем Неопределено или новую таблицу значений.
Процедура ОсновныеДействияФормыкнУстановитьОтбор(Кнопка)
Запрос = Новый Запрос;
//формируем условие отбора
СтрУсловийОтбора = "";
Для каждого ТекПоле Из ПереченьПолейОтбора Цикл
//проверим что установлен флаг, отбирать по данному полю
Если ЭлементыФормы["фл" + ТекПоле].Значение Тогда
СтрУсловийОтбора = СтрУсловийОтбора + ?(ЗначениеЗаполнено(СтрУсловийОтбора), " И ", "")
+ ПолучитьУсловиеЗапроса(ТекПоле);
Если ЭлементыФормы["ВидСравнения" + ТекПоле].Значение = ВидСравнения.Содержит
ИЛИ ЭлементыФормы["ВидСравнения" + ТекПоле].Значение = ВидСравнения.НеСодержит Тогда
Запрос.УстановитьПараметр(ТекПоле, "%" + ЭлементыФормы["ПолеЗначения" + ТекПоле].Значение + "%");
Если ЭлементыФормы.Найти("ПолеЗначения2" + ТекПоле) <> Неопределено Тогда
Запрос.УстановитьПараметр("" + ТекПоле + "2", "%" + ЭлементыФормы["ПолеЗначения2" + ТекПоле].Значение + "%");
КонецЕсли;
Иначе
Запрос.УстановитьПараметр(ТекПоле, ЭлементыФормы["ПолеЗначения" + ТекПоле].Значение);
Если ЭлементыФормы.Найти("ПолеЗначения2" + ТекПоле) <> Неопределено Тогда
Запрос.УстановитьПараметр("" + ТекПоле + "2", ЭлементыФормы["ПолеЗначения2" + ТекПоле].Значение);
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЦикла;
//формируем условие сортировки
СтрУсловийСортировки = "";
Если СписокВыбранныеПоля.Количество() Тогда
Для каждого ТекКолонка Из СписокВыбранныеПоля Цикл
СтрУсловийСортировки = СтрУсловийСортировки + ?(ЗначениеЗаполнено(СтрУсловийСортировки), ", ", "")
+ ТекКолонка.Значение;
КонецЦикла;
КонецЕсли;
//ничего делать не нужно
Если НЕ(ЗначениеЗаполнено(СтрУсловийОтбора)
ИЛИ ЗначениеЗаполнено(СтрУсловийСортировки)) Тогда
ЭтаФорма.Закрыть(Неопределено);
КонецЕсли;
СтрПоляТаблицы = "";
Для каждого ТекКолонка Из ТабДанные.Колонки Цикл
СтрПоляТаблицы = СтрПоляТаблицы + "ТабДанные." + ТекКолонка.Имя + " КАК " + ТекКолонка.Имя + ", "
КонецЦикла;
СтрПоляТаблицы = Лев(СтрПоляТаблицы, СтрДлина(СтрПоляТаблицы) - 2);
ТекстЗапроса = "ВЫБРАТЬ "
+ СтрПоляТаблицы
+ " ПОМЕСТИТЬ втТабДанные
|ИЗ &ТабДанные КАК ТабДанные
|;
|ВЫБРАТЬ "
+ СтрПоляТаблицы
+ " ИЗ втТабДанные КАК ТабДанные "
+ ?(ЗначениеЗаполнено(СтрУсловийОтбора), " ГДЕ " + СтрУсловийОтбора, "")
+ ?(ЗначениеЗаполнено(СтрУсловийСортировки), " УПОРЯДОЧИТЬ ПО " + СтрУсловийСортировки, "")
;
Запрос.Текст = ТекстЗапроса;
Запрос.УстановитьПараметр("ТабДанные", ТабДанные);
ТабДанные = Запрос.Выполнить().Выгрузить();
ЭтаФорма.Закрыть(ТабДанные);
КонецПроцедуры
Возможно, эта обработка кому и поможет.
UPD (26/03/2016): Для дат при выборе вида сравнения интервал, добавил кнопку выбора периода.