Динамическая фильтрация в справочнике при вводе наименования

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

Предлагаю способ, наверное уже избитый, но в поиске не нашел.

Смысл решения, практически тоже самое что предложено Ёпрст. На практике это использую почти год.

Фильтрация происходит по набранным символам разделенных пробелами. Сортировка происходит по первому набору символов (до пробела)
Требования: 1С++
Версия: SQL (с DBF сто лет не работал, наверное что-то нужно поменять 🙂 )
Ограничения. Если установлен отбор из диалога 1С, фильтрация не работает (скорее всего я не разобрался как программно снимать отбор, надеюсь в комментах подскажут)

Код приведенный ниже, добавить в нужную форму.

У меня в ГМ при начале работы системы присвоена глРС = СоздатьОбъект(«ODBCRecord»);
и глСтрокаРазрешенныхСимволов = » .,-+*/\_0123456789абвгдеёжзийклмнопрстуфхцчшщъыьэюяabcdefghijklmnopqrstuvwxyz»;
Их необходимо создать и объявить для работы данного алгоритма. 

 

Перем СтрокаСимволов;

Перем ТекФлагИерархическогоСписка;
Перем СпЗн;
Перем ОтборУстановлен;

Процедура ПриУстановкеОтбора(ТипОтбора,ЗначениеОтбора)
   
ОтборУстановлен = ТипОтбора;
КонецПроцедуры

Функция ПолучитьСписокЭлементов(ВидСправочника, СтрокаСимволов)
   
СтрДляПозиции = СтрокаСимволов;
   
Пробел = Найти(СтрДляПозиции,» «);
    Если
Пробел>0 Тогда
       
СтрДляПозиции = Лев(СтрДляПозиции,Пробел1);
    КонецЕсли;
   
ТекстЗапроса = «
    |SELECT ID [Ссылка $Справочник.»
+ВидСправочника+«]
    |   , case when CHARINDEX (‘»
+СтрДляПозиции+«‘, «+ВидСправочника+«.DESCR)=0 then 999 else CHARINDEX (‘»+СтрДляПозиции+«‘, «+ВидСправочника+«.DESCR) end ПозицияВСтроке
    |FROM $Справочник.»
+ВидСправочника+» AS «+ВидСправочника+» With (NOLOCK)
    |WHERE («
+ВидСправочника+«.ISFOLDER >= 0)
    |»
;
    Если
ПустаяСтрока(СтрокаСимволов)=0 Тогда
       
СтрДляЗапроса = «
        |AND («
+ВидСправочника+«.DESCR LIKE ‘%»+СтрЗаменить(СтрокаСимволов,» «,«%’) AND («+ВидСправочника+«.DESCR LIKE ‘%»);
       
СтрДляЗапроса = СтрДляЗапроса + «%’)
        |»
;
       
ТекстЗапроса=ТекстЗапроса+СтрДляЗапроса;
    КонецЕсли;
   
ТекстЗапроса = ТекстЗапроса + «
    |ORDER BY ПозицияВСтроке, «
+ВидСправочника+«.DESCR
    |»
;
   
глРС.ВыполнитьИнструкцию(ТекстЗапроса, СпЗн);
    Возврат
СпЗн;
КонецФункции

Процедура ПриНажатииКнопкиКлавиатуры(_код, , , , _симв, ФСО)
    Если
Лев(Форма.ТекущаяКолонка(),12)=«Наименование» Тогда
        Если
ПустоеЗначение(ОтборУстановлен)=0 Тогда
           
УстановитьОтбор(«»,«»);
            Возврат;
        КонецЕсли;
        Если (
=1) или (=1) или (=1) Тогда
           
ФСО=1;
            Возврат;
        КонецЕсли;
        Если
_код = 27 Тогда
            Если СтрокаСимволов=«» Тогда 
                Фсо = 1
                Возврат;
            КонецЕсли;

            КурсорНаЭлементе = ТекущийЭлемент();
           
СтрокаСимволов = «»;
           
Форма.Наименование.Заголовок(«Наименование»);
            
СпЗн.УдалитьВсе();
            ИспользоватьСписокЭлементов();
            
ИерархическийСписок(ТекФлагИерархическогоСписка,1);
            Попытка
               
АктивизироватьОбъект(КурсорНаЭлементе);
            Исключение
            КонецПопытки;
           
ФСО = 1;
            Возврат;
        ИначеЕсли
_код = 8 Тогда
           
СтрокаСимволов = Лев(СтрокаСимволов, СтрДлина(СтрокаСимволов)-1);
        ИначеЕсли
_симв=«» Тогда
           
ФСО = 1;
            Возврат;
        ИначеЕсли
Найти(глСтрокаРазрешенныхСимволов, Нрег(_симв))>0 Тогда
           
СтрокаСимволов = СтрокаСимволов + _симв;
        Иначе
           
ФСО = 1;
            Возврат;
        КонецЕсли;
       
Форма.Наименование.Заголовок(«Наименование («+СтрокаСимволов+«)»);
       
СпЗн = ПолучитьСписокЭлементов(«Номенклатура», СтрокаСимволов);
       
ИспользоватьСписокЭлементов(СпЗн);
       
ИерархическийСписок(0,0);
       
ФСО = 0;
    КонецЕсли;
КонецПроцедуры

Процедура
ПриОткрытии()
    ТекФлагИерархическогоСписка = ВосстановитьЗначение(«ТекФлагИерархическогоСпискаНоменклатура»);
    СтрокаСимволов = «»;
    СпЗн = СоздатьОбъект(«СписокЗначений»);
КонецПроцедуры

Процедура ПриСменеИерархии(Способ)
    ТекФлагИерархическогоСписка = Способ;
КонецПроцедуры

Процедура ПриЗакрытии()
    СохранитьЗначение(«ТекФлагИерархическогоСпискаНоменклатура»,ТекФлагИерархическогоСписка);
КонецПроцедуры

60 Comments

  1. maxpiter

    (1)Поправил замечания в описании.

    Работаю с SQL, но для DBF алгоритм такой же, возможно код запросов чуток другой.

    p.s. Спасибо за +, от artbear плюс вообще приятно 🙂

    Reply
  2. gutentag

    полезная вещь!

    Reply
  3. Ёпрст

    Только вот по первым символам и так есть поиск в форме списка справочника..

    Reply
  4. Ёпрст

    штатно

    Reply
  5. maxpiter

    (4) вот вредный, видно же что ищет не по первым символам, а сортирует по первым

    Reply
  6. Ёпрст

    (6)

    1.глСтрокаРазрешенныхСимволов — это что за зверь такой ?

    2. не видно вводимых символов на форме (лучше уж тогда через ДобавитьАтрибут добавлять поле, как у A’Dirks-а)

    3. запрос, на сколько я понял выполняется при каждом нажатии на кнопку клавиатуры, если это не эескейп, бекспейс ?

    це-же медленно на большом спраочнике, лучше или начиная с 3-4 символа, или задержку втыкаить, как в софтпоинте сделали

    Reply
  7. Ёпрст

    >>>как программно снять отбор ?

    УстановитьОтбор(«»);

    Reply
  8. maxpiter

    (7)

    1. упустил

    глСтрокаРазрешенныхСимволов = » .,-+*/\_0123456789абвгдеёжзийклмнопрстуфхцчшщъыьэюяabcdefghijklmn­opqrstuvwxyz»;

    набор символов по которым можно выполнять отбор.

    2. видно, они набираются в поле «Наименование»

    3. на справочнике более чем 5к элементов, примлемо. Действительно думал, чтобы начать фильтрацию с 3 символа, но пришел к выводу, что лучше с первого.

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

    (8)

    спасибо, так пробовал, вываливалось с ошибкой, а вот УстановитьОтбор(«»,»»); только сейчас предположил и получилось, хотя второй параметр и написано что необязательный.

    изменил в коде и описание.

    Reply
  9. Ёпрст

    (9) ааа…

    т.е «МАМА Мыла РАМУ» уже не канает для поиска ?

    жаль..

    Reply
  10. maxpiter

    (10) почему не канает-то???? где сказано что не канает?

    уже столько написал, давно бы попробовал 🙂

    Reply
  11. maxpiter

    +11 SQL ищет без учета регистра, если ему конкретно не скажут что нужно учитывать регистр.

    Reply
  12. Ёпрст

    (12) при чем тут то, что ищет скуль ?

    Ты сам ограничил набор вводимых символов — у тебя заглавные символы ввести нельзя.

    :))))

    Reply
  13. Ёпрст

    А ёпт.. Нрег не заметил в Найти..

    Забираю слова обратно

    Reply
  14. maxpiter

    (14) попробуй уже а? и напиши че нить хорошее 🙂

    Reply
  15. maxpiter

    (13) а заглавные ввести нельзя, потому что shift, alt и ctrl вообще из поиска исключаю

    Reply
  16. Ёпрст

    И это, ставить не буду — тёткам удобно видеть весь справочник, им и штатный поиск по первым символам в форме списка устраивает, причем, он штатно «множественный», т.е нашли первое совпадение, потом можно «бегать» по форме списка вверх вниз по этим совпадениям — привыкли так ужо.

    Reply
  17. Ёпрст

    Хотя..ща прикручу, «послушаю» народное мнение..

    🙂

    Reply
  18. maxpiter

    (17) мои тоже привыкли, но когда в списке ароматизаторов около 200 штук и все начинаются Ароматизатор и только потом различие, то проще набрать аром лимон 🙂 и уже бегать глазками по оставшемуся десятку.

    >> привыкли так ужо. — привычка дело может быть навязанной, причем в данном случае 1С 🙂

    Reply
  19. Ёпрст

    Это ..еще недочет:

    в ПриОткрытии, нужно проверить, что флагиерархического просмотра восстановлен..иначе болт

    Reply
  20. maxpiter

    (20) смотри код, это есть

    Reply
  21. Ёпрст

    СпЗн = ПолучитьСписокЭлементов(«Номенклатура»<<?>>);

    {Справочник.Номенклатура.ФормаСписка.ФормаСписка.Модуль(100)}: Недостаточно фактических параметров

    При проверке модуля обнаружены синтаксические ошибки!

    Reply
  22. Ёпрст

    (21) этого нету

    Процедура ПриОткрытии()

    ТекФлагИерархическогоСписка = ВосстановитьЗначение(«ТекФлагИерархическогоСпискаНоменклатура»);

    вот тут болт, ибо нет еще сохраненного «ТекФлагИерархическогоСпискаНоменклатура» при открытии при первом открытии, да и при закрытии сохранять нечего, если иерархию не меняли.

    Reply
  23. maxpiter

    (22) СпЗн = ПолучитьСписокЭлементов(«Номенклатура»,СтрокаСимволов);

    (23) согласен, если пустое значение после ВосстановитьЗначение, то нужно получить текущее

    Reply
  24. Ёпрст

    (24) 🙂

    Это.. при нажатии Эскейп, нужно проверить, если строка символов не пустая (или было уже нажатия и потом удалили символы, короче, что уже есть использоватьсписокэлементов), то ФСО нужно делать = 0, а не 1, иначе справочник закроется.

    Reply
  25. Ёпрст

    ну и это, чариндекс выкинуть из селекта и запихать в ордербай

    Reply
  26. maxpiter

    (26) — дело вкуса 🙂

    Reply
  27. Ёпрст

    (27) дело в быстродействии

    Reply
  28. maxpiter

    (28) ммм, вот это аргумент, в данном случае каждая миллисекунда дорога 🙂

    Reply
  29. Ёпрст

    И это.. фсо всё же поправь для Esc

    Reply
  30. maxpiter

    +29 хотя у меня case в select работает все таки чуток быстрее, может быть кеш.

    Отличие ооочень мизерное. Оставлю как есть 🙂

    Reply
  31. maxpiter

    (30) код который я представил у меня в форме списка, в форме выбора дейстивтельно есть небольшая добавочка

    Если _код = 27 Тогда

    Если СтрокаСимволов=»» Тогда

    Фсо = 1;

    Возврат;

    КонецЕсли;

    ….

    Reply
  32. maxpiter

    Вообще то. зная имя отбора и значение отбора, можно сгенерить условие фильтрации с учетом отбора 🙂 и будет вообще хорошо

    Reply
  33. Dolly_EV

    (0) CHARINDEX для 1SQLite (dbf) чем заменить? :-((

    Reply
  34. Dolly_EV

    +(34) Мдаа… без CHARINDEX на DBF нелогично сортировка получается, юзер не поймет 🙁

    Reply
  35. maxpiter

    (34)версия 1SQLite какая?

    Reply
  36. maxpiter

    (35) есть шанс получить ответ вот здесь http://snegopat.ru/forum/viewforum.php?f=5

    Reply
  37. dumal

    Хорошая вещь. Можно внедрить в тех местах, где народ пользуется 7.7 и даже не планирует переходить на 8ку. Жаль только, sql…

    Reply
  38. maxpiter

    (38) в DBF пока уперлось в CHARINDEX, но может это все таки решаемо?

    Reply
  39. dumal

    Да, я прочитал в комментариях. Решения у меня нет 🙁

    Reply
  40. Dolly_EV

    (36) 1.0.2.4 (уже 1.0.2.6)

    Вместо чариндекс можно конечно огород нагородить с тз и Найти(СтрДляПозиции,Наименование), но скорость потеряется 🙁

    Reply
  41. Ёпрст

    (41) юзай запрос на фоксе — он быстрее и там есть аналог чариндекса — AT()

    Reply
  42. Dolly_EV

    (42) а с монопольностью там нормально? и пример бы в студию

    Reply
  43. Ёпрст

    (43) нормально.

    Ставишь решение от hogik и привет

    Reply
  44. Ёпрст

    +44

    |select id as [Элем $Справочник.Номенклатура]
    |,iif(at(‘туф’,lower(descr))=0,999,at(‘туф’,lower(descr))) as вася
    |from $Справочник.Номенклатура спр
    |where
    |(lowe
    Reply
  45. maxpiter

    (45) таки в Select ? )))))

    Reply
  46. Ёпрст

    (46) я твой код переделал..

    мне лень даже 1cqa открыть

    Reply
  47. Dolly_EV

    (44) ADS муторно :-(… хотя в 2009-м он меня реально спас. Сейчас решил по периферийкам — по дорастанию до критической массы — переводить на SQL

    Reply
  48. Dolly_EV

    (45) дрова для Фокса — достаточно библиотек вот отсюда http://www.1cpp.ru/forum/YaBB.pl?num=1210677779/30 ?

    Reply
  49. Ёпрст

    (48) при чем тут ADS ?!

    Reply
  50. Ёпрст
  51. Dolly_EV

    (51) ааа, я это как-то упустил :-(( думал, ты имеешь ввиду вот эту: http://infostart.ru/public/15211/

    Reply
  52. Dolly_EV

    (45) В ПриОткрытии():

      СтрСоединение = «Provider=VFPOLEDB.1;Data Source=» + КаталогИБ() + «;Exclusive=Yes;Mode=ReadWrite;Collating Sequence=MACHINE»;
    ДБ = СоздатьОбъект(«OLEDBData»);
    Рез = ДБ.Соединение(СтрСоединение);
    лЗапросФокс = ДБ.СоздатьКоманду();
    лЗапросФокс.Выполнить(«EXECSCRIPT(‘SET ANSI OFF’)»);
    лЗапросФокс.Выполнить(«EXECSCRIPT(‘SET REFRESH TO 0,-1’)»);
    лЗапросФокс.Выполнить(«Exec(‘SET TABLEVALIDATE TO 0’)»);
    лЗапросФокс.Отладка(1);

    ТекстЗапроса:

    SELECT
    ID [Ссылка $Справочник.Номенклатура],
    iif(at(‘в’,lower(Номенклатура.DESCR))=0,999,at(‘в’,lower(Номенклатура.DESCR))) AS ПозицияВСтроке
    FROM
    Справочник.Номенклатура AS Номенклатура
    WHERE
    (Номенклатура.ISFOLDER >= 0)
    
    AND (lower(Номенклатура.DESCR) LIKE ‘%в%’)
    
    ORDER BY ПозицияВСтроке,Номенклатура.DESCR
    

    Показать

    лТЗ=лЗапросФокс.ВыполнитьИнструкцию(ТекстЗапроса);

    {Справочник.Номенклатура.ФормаСписка.Основная.Модуль(101)}: FAILED! ICommandText::Execute(): Too many arguments.

    Где засада?

    Reply
  53. Dolly_EV

    (53) все, разобрался.. ВЗЛЕТЕЛО! УРА! осталось только hogika прикрутить, чтобы в монопольном взлетело

    P.S. Теперь и монопольно — спасибо hogik’у

    Reply
  54. maxpiter

    (54) при наборе текста, скорость фильтрации приемлемая?

    Reply
  55. Dolly_EV

    (55) Приемлемо (Номенклатура 25K), причем на dbf через фокса — заметно бастрее получилось, чем через SQLite. На SQL — медленнее, но там у меня еще заморочка с получением остатков.

    Только стоит все-таки наверно с третьего символа начинать фильтровать ?

    и еще: для Esc при НЕпустой СтрокаСимволов надо ФСО=0 — а то форма выбора закрывается (30)

    Reply
  56. maxpiter

    (56) >> Только стоит все-таки наверно с третьего символа начинать фильтровать ?

    Тоже не совсем логично может получиться.

    В качестве идеи для обсуждения. Сделать как в поисковиках.

    При открытии выдавать пустой справочник, при наборе выводить то что нашлось скажем TOP 20 пока не наберет больше 3х символов. Как больше трех набрал выводит все.

    Reply
  57. maxpiter

    +57 ну понятно, что эта опция для каждого может индивидуально настраиваться в настройках пользователя.

    Reply
  58. Dolly_EV

    (56) Пока как есть оставил, пусть юзеры потестят, потом расспросим

    Reply
  59. maxpiter

    (18)(59) какой результат тестов, пользуются юзвери? 🙂

    Reply
  60. Dolly_EV

    (60) из отпуска только сегодня, но судя по тому, что вопросов нет — пользуются, и видимо понравилось))

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *