Примитивное оглавление по колонке таблицы

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

Позволяет для различных строковых колонок таблицы значений на форме добавить оглавление. Выглядит как меню, отбирает по первому символу. Мелочь, но бывает удобно.

Это, честно говоря, фрагмент одной большой задачи, но сделанный для себя, просто для удобства работы с большим объёмом данных.

Что умеет: индексирует указанную колонку коллекции, беря первые символы, и потом по ним устанавливает отбор строк. Символы рассматривает любые, т.к. ориентируется на переданное "оглавление" - строку тех символов, по которым будут сделаны листы оглавления. Если символа в оглавлении нет, он попадёт в раздел "Все". Если символ есть, он попадёт в один из блоков оглавления. Размер блока регулируется. Можно многократно пересоздавать, можно задавать несколько оглавлений (русское и английское, например).

Создаётся выпадающее подменю, состоящее из блоков. При щелчке выполняется отбор всех строк, у которых первый символ входит в блок. Имеющиеся другие отборы строк по возможности оставляются без изменений.

Недостатки: индексация (т.е. заполнение колонки отбора) может занимать длительное время сообразно размерам коллекции. Почему не запрос? Потому что в коллекции могут содержаться значения таких типов, которые запрос не обрабатывает - картинки, допустим. Поэтому инициализацию оглавления лучше делать тогда, когда содержание коллекции уже стабильно.

Исходный код:

// Анализирует оглавление и подключает его использование к полю коллекции (желательно вызывать при инициализации
// или перезаполнении обрабатываемой коллекции), заполняет/перезаполняет список блоков оглавления.
//
// Параметры:
//    рИмяКоллекции - имя реквизита формы типа ДанныеФормыКоллекция, имеющего одноимённый элемент формы "таблица";
//    рИмяПоля - имя реквизита (колонки) коллекции; подразумевается, что есть элемент формы, чьё имя составлено по общим правилам;
//    рВсеОглавления - строка со списком "заглавных" символов, разделённых при необходимости знаком "|", например, буквы алфавита;
//    рРазмерБлока - число, размер фрагмента оглавления; например, при 4 будет А-Г, Д-Ж итд); по умолчанию равен 4.
//
&НаКлиенте
Процедура ДобавитьОглавлениеПоля(рИмяКоллекции,рИмяПоля,рВсеОглавления,рРазмерБлока=0)
    мОглавлений=СтрРазделить(рВсеОглавления,"|");
    //
    рРазмерБлока=?(рРазмерБлока=0,4,рРазмерБлока);
    //
    мБлоков=Новый Массив;
    соотПервыхСимволов=Новый Соответствие;
    //
    Для ыыы=0 По мОглавлений.Количество()-1 Цикл
        рОглавление=мОглавлений.Получить(ыыы);
        рДлина=СтрДлина(рОглавление);
        пози=1; 
        Пока Истина Цикл
            ОбработкаПрерыванияПользователя();
            рБлок=Сред(рОглавление,пози,рРазмерБлока);
            пози=пози+рРазмерБлока;
            рПервыйСимвол=Лев(рБлок,1);
            Для й=2 По рРазмерБлока Цикл
                соотПервыхСимволов.Вставить(Сред(рБлок,й,1),рПервыйСимвол);
            КонецЦикла;
            мБлоков.Добавить(Новый Структура("НомерОглавления,Блок",ыыы,рБлок));
            Если пози>=рДлина Тогда Прервать КонецЕсли;
        КонецЦикла;
    КонецЦикла;
    //
    ДобавитьИндексноеПолеОглавленияИМеню(рИмяКоллекции,рИмяПоля,соотПервыхСимволов,мБлоков);
КонецПроцедуры    
// Добавляет колонку с индексом (первым символом) для отборов оглавления, и элементы формы для его меню;
// является вспомогательной для ДобавитьОглавлениеПоля и не рассчитана на самостоятельный вызов.
&НаСервере
Процедура ДобавитьИндексноеПолеОглавленияИМеню(рИмяКоллекции,рИмяПоля,соотПервыхСимволов,мБлоков)
    Попытка
        мрек=Новый Массив;
        мрек.Добавить(Новый РеквизитФормы(рИмяПоля+"_ИПО",Новый ОписаниеТипов("Строка",,Новый КвалификаторыСтроки(1)),рИмяКоллекции));
        ИзменитьРеквизиты(мрек);
    Исключение
    КонецПопытки;
    //
    рКоллекция=ЭтаФорма[рИмяКоллекции];
    Для каждого стро Из рКоллекция Цикл
        сим=Лев(стро[рИмяПоля],1);
        соотсим=соотПервыхСимволов.Получить(сим);
        Если соотсим=Неопределено Тогда соотсим=сим КонецЕсли;
        стро[рИмяПоля+"_ИПО"]=соотсим;
    КонецЦикла;
    
    заг=Элементы[рИмяКоллекции+рИмяПоля].Заголовок;
    преф="ИПО_"+рИмяКоллекции+"_"+рИмяПоля+"_";
    грэл=Элементы.Найти("ИПО_Вызовы_"+рИмяКоллекции);
    Если грэл=Неопределено Тогда
        грэл=Элементы.Добавить("ИПО_Вызовы_"+рИмяКоллекции,Тип("ГруппаФормы"),Элементы[рИмяКоллекции+"КоманднаяПанель"]);
        грэл.Вид=ВидГруппыФормы.Подменю;
        грэл.Заголовок="Оглавление"+?(ПустаяСтрока(заг),""," ("+заг+")");
    КонецЕсли;        
    //
    ком=ЭтаФорма.Команды.Найти(преф);
    Если ком=Неопределено Тогда
        ком=ЭтаФорма.Команды.Добавить(преф);
        ком.Действие="ОтобратьБлокПоОглавлению";
        ком.Отображение=ОтображениеКнопки.Текст;
    КонецЕсли;
    эл=Элементы.Найти(ком.Имя);
    Если эл=Неопределено Тогда
        эл=Элементы.Добавить(ком.Имя,Тип("КнопкаФормы"),грэл);
        эл.Вид=ВидКнопкиФормы.КнопкаКоманднойПанели;
        эл.ИмяКоманды=ком.Имя;
        эл.Заголовок="Все";
        эл.Пометка=Истина;
    КонецЕсли;    
    //
    Для каждого рБлок Из мБлоков Цикл
        Попытка
            рПервыйСимвол=Лев(рБлок.Блок,1);
            ком=ЭтаФорма.Команды.Добавить(преф+СокрЛП(рБлок.НомерОглавления)+"_"+рПервыйСимвол);
            ком.Действие="ОтобратьБлокПоОглавлению";
            ком.Отображение=ОтображениеКнопки.Текст;
            эл=Элементы.Добавить(ком.Имя,Тип("КнопкаФормы"),грэл);
            эл.Вид=ВидКнопкиФормы.КнопкаКоманднойПанели;
            эл.ИмяКоманды=ком.Имя;
            эл.Заголовок=рПервыйСимвол+" - "+Прав(рБлок.Блок,1);
        Исключение
        КонецПопытки;        
    КонецЦикла;
КонецПроцедуры
// Вызывается командами, созданными для каждого пункта меню оглавления, выполняет установку и снятие отбора
&НаКлиенте
Процедура ОтобратьБлокПоОглавлению(Команда)
    мстро=СтрРазделить(Команда.Имя,"_");
    рИмяКоллекции=мстро.Получить(1);
    рИмяПоля=мстро.Получить(2);
    Если мстро.Количество()=4 Тогда
        сим="";
    Иначе
        сим=мстро.Получить(4); // третьим идёт номер оглавления
    КонецЕсли;
    
    грэл=Элементы.Найти("ИПО_Вызовы_"+рИмяКоллекции);
    Для каждого эл Из грэл.ПодчиненныеЭлементы Цикл
        Если ТипЗнч(эл)=Тип("КнопкаФормы") Тогда эл.Пометка=Ложь КонецЕсли;
    КонецЦикла;
    
    отб=Новый Структура;
    отбСтарый=Элементы[рИмяКоллекции].ОтборСтрок;
    Если ТипЗнч(отбСтарый)<>Тип("ФиксированнаяСтруктура") Тогда отбСтарый=Новый Структура КонецЕсли;
    Для каждого киз Из отбСтарый Цикл отб.Вставить(киз.Ключ,киз.Значение) КонецЦикла;
    Если ПустаяСтрока(сим) Тогда // все пункты
        Попытка отб.Удалить(рИмяПоля+"_ИПО") Исключение КонецПопытки;
    Иначе
        отб.Вставить(рИмяПоля+"_ИПО",сим);
    КонецЕсли;
    Элементы[рИмяКоллекции].ОтборСтрок=Новый ФиксированнаяСтруктура(отб);
    
    Элементы[Команда.Имя].Пометка=Истина;
КонецПроцедуры

 

Пример вызова:

Оглавления="abcdefghijklmnopqrstuvwxyz|ABCDEFGHIJKLMNOPQRSTUVWXYZ";
ДобавитьОглавлениеПоля("ТаблицаПроизводителей", "Название", Оглавления);

См. также

Добавить вознаграждение
Комментарии
1. Сергей Галюк (dj_serega) 205 13.07.16 10:47 Сейчас в теме
Я так понял используется последняя версия 1С?
2. Яков Коган (Yashazz) 1957 13.07.16 14:45 Сейчас в теме
(1) dj_serega, достаточно заменить СтрРазделить на общемодульную РазложитьСтрокуВМассивПодстрок, и всё остальное заработает на любой 8.3 и, думаю, 8.2