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