gifts2017

Группировка списка по текущей колонке

Опубликовал Яков Коган (Yashazz) в раздел Программирование - Практика программирования

Встать на некую ячейку списка, нажать кнопку, сгруппировать список по значениям этой колонки.

Во-первых, залезать в "настройку списка" бывает долго и неудобно.  Это ж догадаться надо, что есть кнопка "Ещё", да и не всегда она есть. Во-вторых, часть колонок может вообще настраиваться динамически, прямо в Предприятии, кодом или профилем или ещё чем-нибудь. И бывают они не просто данными "первого уровня", а разыменованиями через 2-3 точки, вот и поди догадайся, по чему делать группировку.

Поступим проще - у нас есть поле, т.е. текущая колонка, иногда есть её путь к данным и уж точно всегда есть имя. Разберёмся, каким должен быть путь группировки, да и сделаем её по нажатию на одну кнопку. Например, так:

// Функция разбирает путь к данным, известный для элемента, или имя элемента (если оно добавлено динамически),

// возвращает массив путей, соответствующих типам значений фигурирующих полей (обычно из 1 элемента).
// При ошибке возвращает Неопределено.
//
// Параметры:
// аргИмя - имя колонки как элемента формы;
// аргПуть - имя элемента списка, где расположена колонка;
// аргМетаданные - используется при внутренних рекурсивных вызовах, при внешнем вызове не нужен.
//
// Ограничения:
// Многотипное поле, объявленное в конфигураторе или предприятии, не может иметь дальнейшее разыменование;
// Любое дополнительное поле, объявленное в предприятии, не может иметь разыменование более чем на 1 шаг.
//
&НаСервере
Функция ПолучитьПутиКДанным(аргИмя,аргПуть,аргМетаданные=Неопределено)
    Попытка
        мПутей=Новый Массив;

        Если аргМетаданные=Неопределено Тогда // это первый шаг
            #Область ПервыйШаг
                рИмяЭлемента=аргИмя;
                рИмяСписка=аргПуть;
                //
                элСписок=Элементы.Найти(рИмяСписка);
                Если элСписок=Неопределено Тогда Возврат Неопределено КонецЕсли;
                //
                эл=Элементы.Найти(рИмяЭлемента);
                Если эл=Неопределено Тогда // это динамически добавленная колонка
                    рПутьСписка=элСписок.ПутьКДанным;
                    Для каждого элспис Из элСписок.ПодчиненныеЭлементы Цикл
                        Если ТипЗнч(элспис)<>Тип("ПолеФормы") Тогда Продолжить КонецЕсли;
                        Если Лев(рИмяЭлемента,СтрДлина(элспис.Имя))<>элспис.Имя Тогда Продолжить КонецЕсли;
                        // источником является именно это поле, рассмотрим его путь к данным и от него разыменуем
                        рПуть=СтрЗаменить(элспис.ПутьКДанным,рПутьСписка+".","");
                        // разбираем
                        мрек=ЭтаФорма.ПолучитьРеквизиты(рПутьСписка);
                        Для каждого рек Из мрек Цикл
                            Если Лев(рПуть,СтрДлина(рек.Имя))<>рек.Имя Тогда Продолжить КонецЕсли;
                            // рассматриваем по типам найденного реквизита формы
                            метадан=Неопределено;
                            Для каждого рТип Из рек.ТипЗначения.Типы() Цикл
                                метадан=Метаданные.НайтиПоТипу(рТип);
                                Если метадан=Неопределено Тогда Продолжить КонецЕсли; // разыменования глубже всё равно нет
                                рИмяКРазбору=СтрЗаменить(рИмяЭлемента,элспис.Имя,"");
                                Если Лев(рИмяКРазбору,1)="_" Тогда // это был "_", вставленный СКД, а не часть имени реквизита
                                    рИмяКРазбору=Сред(рИмяКРазбору,2); // далее там уже могут быть и свои "_", входящие в имена
                                КонецЕсли;
                                мПутейРек=ПолучитьПутиКДанным(рИмяКРазбору,рПуть,метадан);
                                Если ТипЗнч(мПутейРек)=Тип("Массив") Тогда
                                    Для каждого знч Из мПутейРек Цикл мПутей.Добавить(знч) КонецЦикла;
                                КонецЕсли;
                            КонецЦикла; // по типам найденного реквизита формы
                        КонецЦикла; // по реквизитам формы, подчинённым реквизиту списка
                        // уже всё нашли
                        Прервать;
                    КонецЦикла; // по подчинённым элементам списка
                    //
                Иначе
                    // простой случай, это штатное поле или его статично заданное разыменование
                    мПутей.Добавить(СтрЗаменить(эл.ПутьКДанным,рИмяСписка+".",""));
                КонецЕсли;
            #КонецОбласти
        Иначе
            #Область РекурсивныйШаг
                рИмяКРазбору=аргИмя;
                мПутей=Новый Массив;
                // ищем среди стандартных и обычных реквизитов левую часть; если находим - откусываем и двигаемся дальше
                метарек=Неопределено;
                Для каждого мтрк Из аргМетаданные.Реквизиты Цикл
                    Если Лев(рИмяКРазбору,СтрДлина(мтрк.Имя))=мтрк.Имя Тогда метарек=мтрк; Прервать КонецЕсли;
                КонецЦикла;
                Если метарек=Неопределено Тогда // обычно это случай стандартного реквизита
                    //В списках фигурируют как Code, Description, DeletionMark, Predefined, Owner, Parent, IsFolder, Date, Number, Posted
                    мПутей.Добавить(аргПуть+"."+рИмяКРазбору);
                Иначе
                    рПутьДальше=аргПуть+"."+метарек.Имя;
                    рИмяДальше=СтрЗаменить(рИмяКРазбору,метарек.Имя,"");
                    Если Лев(рИмяДальше,1)="_" Тогда // это был "_", вставленный СКД, а не часть имени реквизита
                        рИмяДальше=Сред(рИмяДальше,2); // далее там уже могут быть и свои "_", входящие в имена
                    КонецЕсли;
                    Если не ПустаяСтрока(рИмяДальше) Тогда
                        Для каждого рТип Из метарек.Тип.Типы() Цикл
                            метаданДальше=Метаданные.НайтиПоТипу(рТип);
                            Если метаданДальше=Неопределено Тогда Продолжить КонецЕсли; // разыменования глубже всё равно нет
                            мПутейРек=ПолучитьПутиКДанным(рИмяДальше,рПутьДальше,метаданДальше);
                            Если ТипЗнч(мПутейРек)=Тип("Массив") Тогда
                                Для каждого знч Из мПутейРек Цикл мПутей.Добавить(знч) КонецЦикла;
                            КонецЕсли;
                        КонецЦикла;
                    Иначе
                        мПутей.Добавить(рПутьДальше);
                    КонецЕсли;
                КонецЕсли;
            #КонецОбласти
        КонецЕсли;

        Возврат мПутей;
    Исключение
        Сообщить("ПолучитьПутиКДанным, ошибка: "+ОписаниеОшибки(),СтатусСообщения.ОченьВажное);
        Возврат Неопределено;
    КонецПопытки;
КонецФункции

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

Нажатие одной кнопки - и список сгруппирован по значениям текущей колонки)

p.s. Допускаю, что я просмотрел какой-то хитрый случай разыменования для добавленных вручную колонок. Если что, сообщайте, довинтим)

См. также

Подписаться Добавить вознаграждение

Комментарии

1. TMV 22.06.15 21:50
Проблемы со шрифтом в листинге мне причудились? А то глаза болят.
2. Елена Пименова (Bukaska) 23.06.15 10:45
3. TMV 23.06.15 13:40
(2) Bukaska, так отлично, спасибо.
4. Илья Вильчик (TreeDogNight) 28.06.15 10:27
Из приведенного кода понятно, что первый язык авторы был вовсе не 1С =)
5. Яков Коган (Yashazz) 28.06.15 10:44
(4) TreeDogNight, первым был Pascal 5.0, а что навело на эту мысль?
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа