gifts2017

Создаем универсальный механизм отбора и сортировки для управляемых форм

Опубликовал Петр Базелюк (pbazeliuk) в раздел Программирование - Практика программирования

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

Осноные возможноси:

1. Отбор имеет полный функционал как и в 1С Предприятие 8.1;

2. Отсутсвует ошибка при использовании истории отборов (в 1С Предприятии 8.1 если установлен отбор и воспользоватся отбором из истории текущий отбор не отменяется);

3. Возможность использования отборов и сортировки для всех возможных реквизитов, которые присутствуют в таблице и тех которые добавлены через команду формы "Изменить форму" (Например, Номенклатура.Ссылка.Ссылка.ВидНоменклатуры.Код);

4. Сортировка по любому реквизиту в таблице;

5. История отборов размером в 20 элементов;

6. Все построенно на СКД с выводом в таблицу значений, что дает возможность использовать дополнительные поля которые есть в запросе;

7. Минимум серверных вызовов;

8. Для использования в своих разработках достаточно изменить запрос в наборе данных, структуру полей компоновщика (ПриСозданииНаСервере) и подкоректировать таблицу значений для вывода.




Код обработки, работоспособен в конфигурации УТ 11:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
   
//1. Создаем схему компоновки данных
   
СхемаКомпоновкиДанных = Новый СхемаКомпоновкиДанных;
   
//1.1 определяем источник данных для схемы
   
ИсточникДанных = СхемаКомпоновкиДанных.ИсточникиДанных.Добавить();
   
ИсточникДанных.Имя                = "ИсточникДанных";
   
ИсточникДанных.СтрокаСоединения   = "";
   
ИсточникДанных.ТипИсточникаДанных = "Local";
   
//1.2 определяем набор данных
   
НаборДанных = СхемаКомпоновкиДанных.НаборыДанных.Добавить(Тип("НаборДанныхЗапросСхемыКомпоновкиДанных"));
   
НаборДанных.Имя            = "НаборДанных";
   
НаборДанных.ИсточникДанных = "ИсточникДанных";
   
НаборДанных.АвтоЗаполнениеДоступныхПолей = Истина;
   
НаборДанных.Запрос = "
        |ВЫБРАТЬ
        |   СпрНоменклатура.Ссылка КАК Номенклатура,
        |   СвободныеОстатки.ВНаличииОстаток КАК ВНаличии,
        |   СвободныеОстатки.ВРезервеОстаток КАК ВРезерве
        |
        |ИЗ
        |   Справочник.Номенклатура КАК СпрНоменклатура
        |
        |ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.СвободныеОстатки.Остатки КАК СвободныеОстатки
        |ПО СпрНоменклатура.Ссылка = СвободныеОстатки.Номенклатура
        |
        |ГДЕ
        |НЕ СпрНоменклатура.ЭтоГруппа
        |И  СпрНоменклатура.Родитель = &ГруппаНоменклатуры"
;

   
//1.2.1 добавляем поля
   
ПолеНоменклатуры = НаборДанных.Поля.Добавить(Тип("ПолеНабораДанныхСхемыКомпоновкиДанных"));
   
ПолеНоменклатуры.ПутьКДанным = "Номенклатура";
   
ПолеНоменклатуры.Заголовок   = "Номенклатура";
   
ПолеНоменклатуры.Поле        = "Номенклатура";

   
//1.3 определяем ресурсы
    //ПолеРесурса = СхемаКомпоновкиДанных.ПоляИтога.Добавить();
    //ПолеРесурса.Выражение = "";
    //ПолеРесурса.ПутьКДанным = "";

    //2. создаем настройки для схемы
    //НастройкиКомпоновкиДанных = СхемаКомпоновкиДанных.НастройкиПоУмолчанию;
   
АдресСхемыКомпоновкиДанных = ПоместитьВоВременноеХранилище(СхемаКомпоновкиДанных, УникальныйИдентификатор);
   
КомпоновщикНастроек.Инициализировать(Новый ИсточникДоступныхНастроекКомпоновкиДанных(АдресСхемыКомпоновкиДанных));

   
//2.1 определяем структуру
    //2.1.1 добавляем группировку "Номенклатура"
   
ГруппировкаНоменклатуры = КомпоновщикНастроек.Настройки.Структура.Добавить(Тип("ГруппировкаКомпоновкиДанных"));
   
ГруппировкаНоменклатуры.Использование = Истина;

   
//2.2 определим выбранные поля
   
ВыбранноеПоле = ГруппировкаНоменклатуры.Выбор.Элементы.Добавить(Тип("ВыбранноеПолеКомпоновкиДанных"));
   
ВыбранноеПоле.Заголовок     = "Номенклатура";
   
ВыбранноеПоле.Использование = Истина;
   
ВыбранноеПоле.Поле          = Новый ПолеКомпоновкиДанных("Номенклатура");

   
ВыбранноеПоле = ГруппировкаНоменклатуры.Выбор.Элементы.Добавить(Тип("ВыбранноеПолеКомпоновкиДанных"));
   
ВыбранноеПоле.Заголовок     = "ВНаличии";
   
ВыбранноеПоле.Использование = Истина;
   
ВыбранноеПоле.Поле          = Новый ПолеКомпоновкиДанных("ВНаличии");

   
ВыбранноеПоле = ГруппировкаНоменклатуры.Выбор.Элементы.Добавить(Тип("ВыбранноеПолеКомпоновкиДанных"));
   
ВыбранноеПоле.Заголовок     = "ВРезерве";
   
ВыбранноеПоле.Использование = Истина;
   
ВыбранноеПоле.Поле          = Новый ПолеКомпоновкиДанных("ВРезерве");

   
ГруппировкаНоменклатуры.Порядок.Элементы.Добавить(Тип("АвтоЭлементПорядкаКомпоновкиДанных"));
КонецПроцедуры

&НаКлиенте
Процедура ПриОткрытии(Отказ)
   
//Проводим инициализацию отборов из загруженных данных при последнем сохранении
   
ИнициализироватьОтборы();
   
//Обновляем пометки кнопок для визуального восприятия отборов
   
ОбновитьДанныеОтбора();
КонецПроцедуры

&НаСервере
Процедура ИнициализироватьОтборы()
   
//Список значений "ИсторияОтборов" хранит историю отборов, максимум 20 элементов
   
Для і=0 По ИсторияОтборов.Количество()-1 Цикл
       
//Получаем имя команды которая соответствует отбору
       
ИмяКоманды = ИсторияОтборов[і].Значение.ИмяКоманды;
       
//Получаем представление отбора, которое является аналогичным 1С 8.1
       
Представление = ПолучитьПредставлениеОтбора(ИсторияОтборов[і].Значение.МассивОтборов);
       
//Динамически добавляем команду формы и добавляем элемент формы, который привязываем к команде формы
       
ДобавитьКомандуКФорме(ИмяКоманды, Представление);
    КонецЦикла;
КонецПроцедуры

&НаКлиенте
Процедура ИерархияНоменклатурыПередНачаломИзменения(Элемент, Отказ)
   
//Запрет изменения элементов пользователю
   
Отказ = Истина;
КонецПроцедуры

&НаКлиенте
Процедура ИерархияНоменклатурыПередУдалением(Элемент, Отказ)
   
//Запрет удаления элементов пользователю
   
Отказ = Истина;
КонецПроцедуры

&НаКлиенте
Процедура ИерархияНоменклатурыПередНачаломДобавления(Элемент, Отказ, Копирование, Родитель, Группа)
   
//Запрет добавления элементов пользователю
   
Отказ = Истина;
КонецПроцедуры

&НаКлиенте
Процедура ИерархияНоменклатурыПриАктивизацииСтроки(Элемент)
   
//Так как это пример, решил упростить задачу - не обрабатывать пустую ссылку
   
Если Элемент.ТекущаяСтрока.Пустая() Тогда
       
ТаблицаНоменклатуры.Очистить();
    Иначе
       
СформироватьКлиент(Элемент.ТекущаяСтрока);
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура СформироватьКлиент(ГруппаНоменклатуры, Отбор = Ложь, Сортировка = Ложь, Идентификатор = Неопределено, ИмяЭлемента = Неопределено)
    Перем
ПараметрыОтбора;
   
//Запомним данные, возможно нам понадобится востановить курсор пользователя
   
ТекущиеДанные = Элементы.ТаблицаНоменклатуры.ТекущиеДанные;
    Если НЕ
ТекущиеДанные = Неопределено Тогда
        
ПараметрыОтбора = Новый Структура("Номенклатура", ТекущиеДанные.Номенклатура);
    КонецЕсли;

   
СформироватьСервер(ГруппаНоменклатуры, Отбор, Сортировка, Идентификатор, ИмяЭлемента);
   
//Обновляем пометки кнопок для визуального восприятия отборов
   
ОбновитьДанныеОтбора();

   
//Востанавливаем курсор на позицию, если она не пропала из выгрузки
   
Если НЕ ПараметрыОтбора = Неопределено Тогда
       
Массив = ТаблицаНоменклатуры.НайтиСтроки(ПараметрыОтбора);
        Если
Массив.Количество() Тогда Элементы.ТаблицаНоменклатуры.ТекущаяСтрока = Массив[0].ПолучитьИдентификатор(); КонецЕсли;
    КонецЕсли;
КонецПроцедуры

&НаСервере
Процедура СформироватьСервер(ГруппаНоменклатуры, Отбор = Ложь, Сортировка = Ложь, Идентификатор = Неопределено, ИмяЭлемента = Неопределено)
    Перем
Значение, ВремОбъект;
   
//Получаем СКД из временного хранилища
   
СхемаКомпоновкиДанных   = ПолучитьИзВременногоХранилища(АдресСхемыКомпоновкиДанных);
   
КомпоновщикНастроек.Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("ГруппаНоменклатуры", ГруппаНоменклатуры);
   
//У пользователя есть возможность изменять форму, нужно проверить имя реквизита - возможно реквизит был добавлен через "Изменить форму..."
   
Если Отбор ИЛИ НЕ Сортировка = Ложь Тогда
       
ТекущиеДанные = ТаблицаНоменклатуры.НайтиПоИдентификатору(Идентификатор);
       
//Проверяем есть ли реквизит
       
РеквизитИзТаб = ТекущиеДанные.Свойство(ИмяЭлемента, Значение);
        Если
РеквизитИзТаб Тогда
            Если
Отбор Тогда
               
ДобавитьОтборПоЗначению(КомпоновщикНастроек, ИмяЭлемента, Значение);
               
ОбновитьИсториюОтборов(КомпоновщикНастроек, ИсторияОтборов);
            Иначе
               
ДобавитьСортировку(КомпоновщикНастроек, ИмяЭлемента, Сортировка);
            КонецЕсли;
        Иначе
           
//Реквизита нет в таблице, разбиваем ИмяЭлемента на слова
           
МассивИмен = ПолучитьМассивИмен(ИмяЭлемента);
           
Колич_Имен = МассивИмен.Количество() - 1;

           
//Данный цикл предназначен для поиска реквизита ссылочного типа, который является родителем реквизита по которому
            //выполняется отбор или сортировка
           
Для i = 0 По Колич_Имен Цикл
                Если
ТекущиеДанные.Свойство(МассивИмен[i], ВремОбъект) Тогда
                    Если
Найти(XMLТипЗнч(ВремОбъект).ИмяТипа, "Ref") = 0 Тогда
                       
//Добавлять дополнительные поля возможно только из реквизитов ссылочного типа
                       
ВызватьИсключение "Возникла неизвестная ошибка. Реквизит имеет не ссылочный тип: " + ИмяЭлемента;
                    КонецЕсли;
                   
ИмяЭлемента = МассивИмен[i];
                   
i=i+1;
                    Прервать;
                ИначеЕсли
i+1 <= Колич_Имен Тогда
                   
МассивИмен[i+1] = МассивИмен[i] + "_" + МассивИмен[i+1];
                Иначе
                    ВызватьИсключение
"Возникла неизвестная ошибка. В таблице нет данных о имени: " + ИмяЭлемента;
                КонецЕсли;
            КонецЦикла;

           
//Выполняем построение адреса реквизита по которому нужно выполнить отбор или сортировку
           
АдресРеквизита = "";
           
МетаВремЗначение = ВремОбъект.Метаданные();
            Пока
i <= Колич_Имен Цикл
               
ВремЗначение = МетаВремЗначение.Реквизиты.Найти(МассивИмен[i]);
                Если НЕ
ВремЗначение = Неопределено Тогда
                   
АдресРеквизита = АдресРеквизита + МассивИмен[i];
                   
формироватьАдресРеквизита(i, Колич_Имен, МетаВремЗначение, ВремЗначение, АдресРеквизита);
                Иначе
                    Попытка
                       
ВремЗначение = МетаВремЗначение.СтандартныеРеквизиты[МассивИмен[i]];
                       
АдресРеквизита = АдресРеквизита + МассивИмен[i];
                       
формироватьАдресРеквизита(i, Колич_Имен, МетаВремЗначение, ВремЗначение, АдресРеквизита);
                    Исключение
                       
МассивИмен[i+1] = МассивИмен[i] + "_" + МассивИмен[i+1];
                    КонецПопытки;
                КонецЕсли;
               
i=i+1;
            КонецЦикла;

            Если
Отбор Тогда
               
ДобавитьОтборПоЗначению(КомпоновщикНастроек, ИмяЭлемента + ?(ПустаяСтрока(АдресРеквизита), "", "." + АдресРеквизита), ПолучитьЗначениеРеквизита(АдресРеквизита, ВремОбъект));
               
ОбновитьИсториюОтборов(КомпоновщикНастроек, ИсторияОтборов);
            Иначе
               
ДобавитьСортировку(КомпоновщикНастроек, ИмяЭлемента + ?(ПустаяСтрока(АдресРеквизита), "", "." + АдресРеквизита), Сортировка);
            КонецЕсли;
        КонецЕсли;
    КонецЕсли;

   
//3. готовим макет
   
КомпоновщикМакетаДанных = Новый КомпоновщикМакетаКомпоновкиДанных;
   
МакетКомпоновкиДанных = КомпоновщикМакетаДанных.Выполнить(СхемаКомпоновкиДанных, КомпоновщикНастроек.Настройки, , , Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));

   
//4. исполняем макет
   
ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных;
   
ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновкиДанных);

   
//5. выводим результат
   
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
   
ТаблицаНоменклатуры.Загрузить(ПроцессорВывода.Вывести(ПроцессорКомпоновкиДанных));
КонецПроцедуры

&НаСервере
Процедура ДобавитьСортировку(КомпоновщикНастроек, ИмяЭлемента, Направление)
   
ЭлементыПорядка = КомпоновщикНастроек.Настройки.Порядок.Элементы;
   
ЭлементыПорядка.Очистить();
   
ЭлементПорядка = ЭлементыПорядка.Добавить(Тип("ЭлементПорядкаКомпоновкиДанных"));
   
ЭлементПорядка.Использование = Истина;
   
ЭлементПорядка.ТипУпорядочивания = Направление;
   
ЭлементПорядка.Поле = Новый ПолеКомпоновкиДанных(ИмяЭлемента);
КонецПроцедуры

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

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

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

    Если
МассивОтборов.Количество() Тогда
       
ПредставлениеОтбора = ПолучитьПредставлениеОтбора(МассивОтборов);
       
КоличествоЭлементов = ИсторияОтборов.Количество()-1;
        Для
i=0 По КоличествоЭлементов Цикл
           
//Если отбор найден перемещаем команду в начало списка, так же в списке значений изменяем положение отбора
           
Если ПредставлениеОтбора = ИсторияОтборов[i].Представление Тогда
               
ПереместитьКомандуФормы(ИсторияОтборов[i].Значение.ИмяКоманды, ИсторияОтборов[0].Значение.ИмяКоманды);
               
ИсторияОтборов.Сдвинуть(i, -i);
                Прервать;
           
//Это новый элемент создаем вначале списка значений, так же команду устанавливаем вначало списка
           
ИначеЕсли i = КоличествоЭлементов Тогда
               
ДобавитьКомандуКФорме(ИмяКоманды, ПредставлениеОтбора, ИсторияОтборов[0].Значение.ИмяКоманды);
               
ИсторияОтборов.Вставить(0, Новый Структура("ИмяКоманды, МассивОтборов", ИмяКоманды, МассивОтборов), ПредставлениеОтбора);
            КонецЕсли;
        КонецЦикла;
       
//Элементов еще нет, создаем первые элементы
       
Если КоличествоЭлементов < 0 Тогда
           
ДобавитьКомандуКФорме(ИмяКоманды, ПредставлениеОтбора);
           
ИсторияОтборов.Вставить(0, Новый Структура("ИмяКоманды, МассивОтборов", ИмяКоманды, МассивОтборов), ПредставлениеОтбора);
        КонецЕсли;
    КонецЕсли;

   
//Элементов больше 20, удаляем лишнее
   
Если ИсторияОтборов.Количество() = 21 Тогда
       
УдалитьКомандуФормы(ИсторияОтборов[20].Значение.ИмяКоманды);
       
ИсторияОтборов.Удалить(20);
    КонецЕсли;
КонецПроцедуры

&НаСервере
Функция ПолучитьПредставлениеОтбора(МассивОтборов)
   
ПредставлениеОтбора = "";
   
КоличествоЭлементов = МассивОтборов.Количество()-1;
    Для
i=0 По КоличествоЭлементов Цикл
       
ПредставлениеОтбора = ПредставлениеОтбора + МассивОтборов[i].ЛевоеЗначение  + " "
                                                 
+ МассивОтборов[i].ВидСравнения   + " "
                                                 
+ МассивОтборов[i].ПравоеЗначение + ?(i<КоличествоЭлементов, ", ", "");
    КонецЦикла;
    Возврат
ПредставлениеОтбора;
КонецФункции

&НаСервере
Процедура ДобавитьКомандуКФорме(ИмяКоманды, Представление, ИмяПозицииВставки = Неопределено)
   
Команда = Команды.Добавить(ИмяКоманды);
   
Команда.Действие = "ОтборИстория";
   
Команда.Заголовок = Представление;
   
КомандаФормы = Элементы.Вставить(Команда.Имя, Тип("КнопкаФормы"), Элементы.ИсторияОтборов, Элементы.Найти(ИмяПозицииВставки));
   
КомандаФормы.ИмяКоманды = Команда.Имя;
   
КомандаФормы.Заголовок  = Представление;
   
КомандаФормы.Вид  = ВидКнопкиФормы.КнопкаКоманднойПанели;
КонецПроцедуры

&НаСервере
Процедура ПереместитьКомандуФормы(ИмяКоманды, ИмяПозицииПеремещения)
   
Элементы.Переместить(Элементы.Найти(ИмяКоманды), Элементы.ИсторияОтборов, Элементы.Найти(ИмяПозицииПеремещения));
КонецПроцедуры

&НаСервере
Процедура УдалитьКомандуФормы(ИмяКоманды)
   
Элементы.Удалить(Элементы.Найти(ИмяКоманды));
   
Команды.Удалить(Команды.Найти(ИмяКоманды));
КонецПроцедуры

&НаСервере
Функция ПолучитьЗначениеРеквизита(АдресРеквизита, Объект)
    Перем
ЗначениеРеквизита;
    Выполнить(
"ЗначениеРеквизита = Объект." + АдресРеквизита + ";");
    Возврат
ЗначениеРеквизита;
КонецФункции

&НаСервере
Функция ПолучитьМассивИмен(ИмяЭлемента)
   
МассивСлов = Новый Массив;
   
ЧислоВхождений = СтрЧислоВхождений(ИмяЭлемента, "_");
    Если
ЧислоВхождений = 0 Тогда
       
МассивСлов.Добавить(ИмяЭлемента);
    Иначе
        Для
Итератор = 0 По ЧислоВхождений - 1 Цикл
           
Разделитель = Найти(ИмяЭлемента, "_");
           
МассивСлов.Добавить(Лев(ИмяЭлемента, Разделитель - 1));
           
ИмяЭлемента = Прав(ИмяЭлемента, СтрДлина(ИмяЭлемента) - Разделитель);
        КонецЦикла;
       
МассивСлов.Добавить(ИмяЭлемента);
    КонецЕсли;
    Возврат
МассивСлов;
КонецФункции

&НаСервере
Процедура формироватьАдресРеквизита(i, Колич_Имен, МетаВремЗначение, ВремЗначение, АдресРеквизита)
    Если
i + 1 <= Колич_Имен Тогда
       
//Из описания типа получаем метаданные
       
МетаВремЗначение = ВремЗначение.Тип.ПривестиЗначение(Неопределено).Метаданные();
       
АдресРеквизита = АдресРеквизита + ".";
    КонецЕсли;
КонецПроцедуры

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

&НаКлиенте
Процедура ОтборИСортировка(Команда)
   
Результат = ОткрытьФормуМодально("ВнешняяОбработка.УниверсальныйОтбор.Форма.ФормаНастройки", Новый Структура("КомпоновщикНастроек", КомпоновщикНастроек), ЭтаФорма);
    Если
ТипЗнч(Результат) = Тип("КомпоновщикНастроекКомпоновкиДанных") Тогда
       
КомпоновщикНастроек = Результат;
       
ОбновитьДанныеОтбора();
       
ОбновитьИсториюОтборов(КомпоновщикНастроек, ИсторияОтборов);
       
ТСтрока = Элементы.ИерархияНоменклатуры.ТекущаяСтрока;
        Если НЕ
ТСтрока.Пустая() Тогда СформироватьКлиент(ТСтрока); КонецЕсли;
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура ОтборПоЗначению(Команда)
   
ТСтрока  = Элементы.ИерархияНоменклатуры.ТекущаяСтрока;
   
ТДанные  = Элементы.ТаблицаНоменклатуры.ТекущиеДанные;
   
ТЭлемент = Элементы.ТаблицаНоменклатуры.ТекущийЭлемент;
    Если НЕ
ТСтрока.Пустая() И НЕ Элементы.ТаблицаНоменклатуры.ТекущиеДанные = Неопределено Тогда
       
ИмяЭлемента = ТЭлемент.Имя;
       
СформироватьКлиент(ТСтрока, Истина, , ТДанные.ПолучитьИдентификатор(), ИмяЭлемента);
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура ОтключитьОтбор(Команда)
   
ОбновитьДанныеОтбора(Истина);
   
ТСтрока = Элементы.ИерархияНоменклатуры.ТекущаяСтрока;
    Если НЕ
ТСтрока.Пустая() Тогда СформироватьКлиент(ТСтрока); КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура ОтборИстория(Команда)
   
//Ищем в истории отборов отбор соответствующий имени команды
   
Перем МассивОтборов;
    Для
i=0 По ИсторияОтборов.Количество()-1 Цикл
        Если
ИсторияОтборов[i].Значение.ИмяКоманды = Команда.Имя Тогда
           
МассивОтборов = ИсторияОтборов[i].Значение.МассивОтборов;
           
ПереместитьКомандуФормы(Команда.Имя, ИсторияОтборов[0].Значение.ИмяКоманды);
            Если
ИсторияОтборов.Количество() > 1 Тогда ИсторияОтборов.Сдвинуть(i, -i); КонецЕсли;
            Прервать;
        КонецЕсли;
    КонецЦикла;

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

   
//Выполняем запрос
   
ТСтрока = Элементы.ИерархияНоменклатуры.ТекущаяСтрока;
    Если НЕ
ТСтрока.Пустая() Тогда
       
СформироватьКлиент(ТСтрока);
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура СортироватьПоВозрастанию(Команда)
   
ТСтрока  = Элементы.ИерархияНоменклатуры.ТекущаяСтрока;
   
ТДанные  = Элементы.ТаблицаНоменклатуры.ТекущиеДанные;
   
ТЭлемент = Элементы.ТаблицаНоменклатуры.ТекущийЭлемент;
    Если НЕ
ТСтрока.Пустая() И НЕ Элементы.ТаблицаНоменклатуры.ТекущиеДанные = Неопределено Тогда
       
ИмяЭлемента = ТЭлемент.Имя;
       
СформироватьКлиент(ТСтрока, , НаправлениеСортировкиКомпоновкиДанных.Возр, ТДанные.ПолучитьИдентификатор(), ИмяЭлемента);
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура СортироватьПоУбыванию(Команда)
   
ТСтрока  = Элементы.ИерархияНоменклатуры.ТекущаяСтрока;
   
ТДанные  = Элементы.ТаблицаНоменклатуры.ТекущиеДанные;
   
ТЭлемент = Элементы.ТаблицаНоменклатуры.ТекущийЭлемент;
    Если НЕ
ТСтрока.Пустая() И НЕ Элементы.ТаблицаНоменклатуры.ТекущиеДанные = Неопределено Тогда
       
ИмяЭлемента = ТЭлемент.Имя;
       
СформироватьКлиент(ТСтрока, , НаправлениеСортировкиКомпоновкиДанных.Убыв, ТДанные.ПолучитьИдентификатор(), ИмяЭлемента);
    КонецЕсли;
КонецПроцедуры

Скачать файлы

Наименование Файл Версия Размер
Универсальный отбор 252
.epf 19,53Kb
02.05.12
252
.epf 19,53Kb Скачать

См. также

Подписаться Добавить вознаграждение
Комментарии
0. Петр Базелюк (pbazeliuk) 02.05.12 10:01
Причиной этого труда стало: отсутствие привычной кнопки "Отбор по значению в текущей колонке", некоторые проблемы с динамическими списками, отсутствие истории отборов, авто восстановления настроек отборов при перезапуске формы (динамических списков), а так же стремление увеличить функциональность отборов и сортировок с учетом возможностей управляемых форм.

Перейти к публикации

1. zavedeev (zavedeev) 03.05.12 13:25
Отлично. Спасибо!!!
pbazeliuk; +1 Ответить
2. Dmitry Afanasyev (afanasko) 03.05.12 16:11
Отличная вещь! Побежал прикручивать к своим конфам.
pbazeliuk; +1 Ответить
3. Дандронтий Крузенштерн (dandrontiy) 04.05.12 08:18
Очень интересно. Получается не только чисто отбор можно использовать, но еще и дополнительные запросы.
Функционал явно превосходит механизм отборов в 1с 8.1
Так можно подумать и добавить спец запросы (сделанные не пользователем, а разрабочиком и прикрученные к механизму отбора) а пользователь будет задавать только конечные параметры. Например отбор по реквизитам подчиненного документа.

Плюс однозначно!
Но с кодом еще придется поразбираться ;-) не тривиально всё.
4. Makc Saipl (Saipl) 04.05.12 08:28
Работа проделана конечно большая и это +, надеюсь что данный сервис появится на уровне платформы (то что до сих пор не появился это -)
5. Василий Антонов (khaoos) 05.05.12 06:35
Хорошая серьезная разработка. Автор молодец. Однозначно плюс, к тому же еще и код выложил!
6. Александр Гуляев (gavrikprog) 05.05.12 16:43
7. Евгений Шабалин (xzorkiix) 05.05.12 17:25
2. Отсутсвует ошибка при использовании истории отборов (в 1С Предприятии 8.1 если установлен отбор и воспользоватся отбором из истории текущий отбор не отменяется);


Не знал даже этого.
8. Екатерина Горобец (aviaye) 10.05.12 05:58
Очень этого не хватало, спасибо автору) И пошла пробовать-экспериментировать
9. Денис (Den_D) 10.05.12 11:49
Вот это штукенция очень надо. Спасибо огромное!
10. Алексей Ан (An-Aleksey) 10.05.12 13:35
То что доктор прописал :) Однозначно +
11. nizar (nizar) 11.05.12 15:26
12. Сергей Федоров (Bober777) 02.08.12 00:11
13. Яков Коган (Yashazz) 15.11.12 18:02
Красиво, но для добавляемых колонок нежизнеспособно, ибо сделать такой универсал очень трудно.

Вот есть у меня динам.список по выборке, а выборка строится с использованием механизма характеристик. И вот хочу я отобрать по колонке, принудительно выведенной на интерфейс. И тут, подозреваю, нифига не выйдет.
Да, и если в именах полей, сами по себе, есть знаки подчёркивания - тоже сомневаюсь в безошибочности.
14. Baza (pbazeliuk) 13.12.12 23:41
(13) Yashazz, Подчеркивания обрабатываются вот этим куском, если это добавленая колонка, тогда поиск идет по метаданным на совпадение (В случае, когда в метаданных есть "Полное_Наименование" оно обработается правильно). Проблема присутствует, если в выборке множество реквизитов ссылочного типа, а не один.

Пока i <= Колич_Имен Цикл
ВремЗначение = МетаВремЗначение.Реквизиты.Найти(МассивИмен[i]);
Если НЕ ВремЗначение = Неопределено Тогда
АдресРеквизита = АдресРеквизита + МассивИмен[i];
формироватьАдресРеквизита(i, Колич_Имен, МетаВремЗначение, ВремЗначение, АдресРеквизита);
Иначе
Попытка
ВремЗначение = МетаВремЗначение.СтандартныеРеквизиты[МассивИмен[i]];
АдресРеквизита = АдресРеквизита + МассивИмен[i];
формироватьАдресРеквизита(i, Колич_Имен, МетаВремЗначение, ВремЗначение, АдресРеквизита);
Исключение
МассивИмен[i+1] = МассивИмен[i] + "_" + МассивИмен[i+1];
КонецПопытки;
КонецЕсли;
i=i+1;
КонецЦикла;


Почти все нюансы эти уже исправлены, но руки не доходят обновить публикацию.
15. михаил петров (m1kll) 14.12.12 05:59
16. Алекс (tommyknocker) 25.12.12 19:47
Отличная идея. Пользователям жутко не хватает этих кнопок. Вроде как в УФ это и есть, но где раньше было одно нажатие, теперь нужно 2-3 в лучшем случае, а при составных отборах и того больше.
Еще бы как-то это в общую команду оформить...
17. program program (prodines) 26.04.13 14:53
Да как этим пользоваться, объясните... (для тех, кто управляемые формы видит в первый раз)

У меня управляемая форма списка реализаций товаров и услуг. Основной реквизит - Список с типом ДинамическийСписок. Чекбокс Произвольный запрос установлен.

В скаченной обработке среди реквизитов есть таблица значений. Значит, работаем вместо динамического списка с таблицей значений, что ли?

И окна "Иерархия номенклатуры" у меня нет = значит, из программного кода придётся вырезать куски кода под него?
18. pbazelyuk (pbazeliuk) 27.04.13 18:20
(17) prodines, это как пример. Для динамического списка эта публикация не подойдет. Для динамического списка все совсем иначе и в описании еще написано:
отсутствие привычной кнопки "Отбор по значению в текущей колонке", некоторые проблемы с динамическими списками, отсутствие истории отборов, авто восстановления настроек отборов при перезапуске формы (динамических списков)
.
19. Z Lu (validat) 09.06.13 14:05
Скачал. Опыта маловато. Буду пробовать. Сортировка нужна в платформе, однозначно.
20. Елена Ситникова (lesenoklenok) 20.01.15 21:50
Отличная статья! Очень помогла! Спасибо автору!
21. Иван Дижа (IDija) 24.11.15 11:21
Подскажите а как бы этот функционал использовать в форме выбора? Чтобы возвращало значение?
22. Петр Базелюк (pbazeliuk) 24.11.15 13:27
(21) IDija, можете детально описать проблему, не понятно зачем это использовать в форме выбора?
23. Иван Дижа (IDija) 24.11.15 14:18
(22) pbazeliuk, В документе при выборе в ТЧ Номенклатуры нет истории предыдущего выбора. Что бы при написании наименования предлагалась предыдущие варианты поиска.
Может есть и вариант попроще, но не шел?
24. Петр Базелюк (pbazeliuk) 24.11.15 18:50
(23) IDija, историю выбора номенклатуры нужно реализовывать самому. Задача по своей сути очень простая, если не нужно использовать переопределение вызовов и динамическое подключение функциональности.
25. Александр Зорин (Manticor) 04.07.16 17:48
Подскажите пожалуйста, возможно ли данный механизм реализовать под обычные формы для табличного поля с типом таблица значений??
26. Петр Базелюк (pbazeliuk) 05.07.16 08:27
(25) Manticor, для обычных форм можно использовать только идею, но не сам код что тут представлен, нужны множественные доработки.